Merge changes from topics "kelvin_cleanops", "kelvin_encode_fix", "kelvin_fpu" * changes: [ml_top/hw] Remove scalar FPU from Kelvin [ml_top/hw] Remove unused ops in Kelvin [ml_top/hw] Update kelvin with scalar encoding fix
diff --git a/hw/bitstream/vivado/BUILD b/hw/bitstream/vivado/BUILD index 50936ff..5da3217 100644 --- a/hw/bitstream/vivado/BUILD +++ b/hw/bitstream/vivado/BUILD
@@ -91,7 +91,7 @@ name = "otp_mmi", testonly = True, srcs = [":fpga_nexus"], - output_group = "opt_mmi", + output_group = "otp_mmi", tags = ["manual"], )
diff --git a/hw/top_matcha/dv/chip_sim_cfg.hjson b/hw/top_matcha/dv/chip_sim_cfg.hjson index 164c73a..9057076 100644 --- a/hw/top_matcha/dv/chip_sim_cfg.hjson +++ b/hw/top_matcha/dv/chip_sim_cfg.hjson
@@ -409,98 +409,98 @@ tests: [ { name: chip_sw_smc_isp_wrapper_tpg_64_64_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_isp_wrapper_tpg_64_64_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_env_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_env_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_isp_wrapper_irq_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_isp_wrapper_irq_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_tlul_mailbox_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_tlul_mailbox_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_cam_irq_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_cam_irq_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_ml_sram_smoketest - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_ml_dmem_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_kelvin_hello_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_kelvin_hello_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_ml_top_irq_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_ml_top_irq_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_supervisor_mode_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_supervisor_mode_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_virtual_memory_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_virtual_memory_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_interrupt_boundary_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_interrupt_boundary_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_lsu_interrupt_boundary_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_lsu_interrupt_boundary_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_page_boundary_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_page_boundary_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_lsu_page_boundary_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_lsu_page_boundary_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] @@ -549,35 +549,35 @@ } { name: chip_sw_smc_i2s_rx_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_i2s_rx_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_i2s_tx_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_i2s_tx_test:6:matcha"] en_run_modes: ["sw_test_mode_test_rom"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_rv_timer_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_rv_timer_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_kelvin_checksum_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_kelvin_checksum_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] } { name: chip_sw_smc_isp_wrapper_test - uvm_test_seq: chip_sw_base_vseq + uvm_test_seq: chip_sw_smc_base_vseq sw_images: ["//sw/device/tests/smc:smc_isp_wrapper_test:6:matcha"] en_run_modes: ["sw_test_mode_test_simple_sec"] run_opts:["+sw_test_timeout_ns=40_000_000"] @@ -667,7 +667,7 @@ { name: chip_sw_sleep_pin_retention uvm_test_seq: chip_sw_sleep_pin_retention_vseq - sw_images: ["//sw/device/tests/sim_dv:sleep_pin_retention_test:1"] + sw_images: ["//sw/device/tests/sim_dv:sleep_pin_retention_test:1:matcha"] en_run_modes: ["sw_test_mode_test_rom"] } { @@ -826,7 +826,7 @@ { name: chip_sw_gpio uvm_test_seq: chip_sw_gpio_vseq - sw_images: ["//sw/device/tests/sim_dv:gpio_test:1"] + sw_images: ["//sw/device/tests/sim_dv:gpio_test:1:matcha"] en_run_modes: ["sw_test_mode_test_rom"] } { @@ -1092,7 +1092,7 @@ { name: chip_sw_pwrmgr_random_sleep_all_reset_reqs uvm_test_seq: chip_sw_random_sleep_all_reset_vseq - sw_images: ["//sw/device/tests/sim_dv:pwrmgr_random_sleep_all_reset_reqs_test:1"] + sw_images: ["//sw/device/tests/sim_dv:pwrmgr_random_sleep_all_reset_reqs_test:1:matcha"] en_run_modes: ["sw_test_mode_test_rom"] run_opts: ["+sw_test_timeout_ns=50_000_000"] run_timeout_mins: 120 @@ -1100,7 +1100,7 @@ { name: chip_sw_pwrmgr_deep_sleep_all_reset_reqs uvm_test_seq: chip_sw_deep_sleep_all_reset_vseq - sw_images: ["//sw/device/tests/sim_dv:pwrmgr_deep_sleep_all_reset_reqs_test:1"] + sw_images: ["//sw/device/tests/sim_dv:pwrmgr_deep_sleep_all_reset_reqs_test:1:matcha"] en_run_modes: ["sw_test_mode_test_rom"] run_opts: ["+sw_test_timeout_ns=50_000_000"] run_timeout_mins: 120 @@ -1108,28 +1108,28 @@ { name: chip_sw_pwrmgr_normal_sleep_all_reset_reqs uvm_test_seq: chip_sw_deep_sleep_all_reset_vseq - sw_images: ["//sw/device/tests/sim_dv:pwrmgr_normal_sleep_all_reset_reqs_test:1"] + sw_images: ["//sw/device/tests/sim_dv:pwrmgr_normal_sleep_all_reset_reqs_test:1:matcha"] en_run_modes: ["sw_test_mode_test_rom"] run_timeout_mins: 120 } { name: chip_sw_pwrmgr_sleep_power_glitch_reset uvm_test_seq: chip_sw_main_power_glitch_vseq - sw_images: ["//sw/device/tests/sim_dv:pwrmgr_sleep_power_glitch_test:1"] + sw_images: ["//sw/device/tests/sim_dv:pwrmgr_sleep_power_glitch_test:1:matcha"] en_run_modes: ["sw_test_mode_test_rom"] run_opts: ["+bypass_alert_ready_to_end_check=1"] } { name: chip_sw_pwrmgr_deep_sleep_power_glitch_reset uvm_test_seq: chip_sw_deep_power_glitch_vseq - sw_images: ["//sw/device/tests/sim_dv:pwrmgr_deep_sleep_power_glitch_test:1"] + sw_images: ["//sw/device/tests/sim_dv:pwrmgr_deep_sleep_power_glitch_test:1:matcha"] en_run_modes: ["sw_test_mode_test_rom"] run_opts: ["+bypass_alert_ready_to_end_check=1"] } { name: chip_sw_pwrmgr_random_sleep_power_glitch_reset uvm_test_seq: chip_sw_random_power_glitch_vseq - sw_images: ["//sw/device/tests/sim_dv:pwrmgr_random_sleep_power_glitch_reset_test:1"] + sw_images: ["//sw/device/tests/sim_dv:pwrmgr_random_sleep_power_glitch_reset_test:1:matcha"] en_run_modes: ["sw_test_mode_test_rom"] run_opts: ["+bypass_alert_ready_to_end_check=1", "+sw_test_timeout_ns=24_000_000"] @@ -1629,7 +1629,7 @@ { name: chip_sw_pwrmgr_b2b_sleep_reset_req uvm_test_seq: chip_sw_repeat_reset_wkup_vseq - sw_images: ["//sw/device/tests/sim_dv:pwrmgr_b2b_sleep_reset_test:1"] + sw_images: ["//sw/device/tests/sim_dv:pwrmgr_b2b_sleep_reset_test:1:matcha"] en_run_modes: ["sw_test_mode_test_rom"] run_opts: ["+sw_test_timeout_ns=35_000_000"] run_timeout_mins: 120 @@ -2017,6 +2017,7 @@ "chip_sw_csrng_smoketest", "chip_sw_dma_main_test", "chip_sw_example_flash", + "chip_sw_gpio", "chip_sw_i2c_host_tx_rx", "chip_sw_mem_test", "chip_sw_rom_ctrl_integrity_check", @@ -2070,6 +2071,7 @@ "chip_sw_flash_ctrl_access", "chip_sw_flash_ctrl_access_jitter_en", "chip_sw_flash_ctrl_access_jitter_en_reduced_freq", + "chip_sw_gpio", "chip_sw_hmac_enc", "chip_sw_hmac_smoketest", "chip_sw_i2c_host_tx_rx", @@ -2081,6 +2083,9 @@ "chip_sw_otbn_smoketest", "chip_sw_otp_ctrl_escalation", "chip_sw_otp_ctrl_smoketest", + "chip_sw_pwrmgr_deep_sleep_power_glitch_reset", + "chip_sw_pwrmgr_sleep_power_glitch_reset", + "chip_sw_pwrmgr_sleep_sensor_ctrl_alert_wakeup", "chip_sw_rom_ctrl_integrity_check", "chip_sw_rstmgr_smoketest", "chip_sw_rstmgr_sw_req", @@ -2092,6 +2097,7 @@ "chip_sw_rv_timer_irq", "chip_sw_sensor_ctrl_alert", "chip_sw_sensor_ctrl_status", + "chip_sw_sleep_pin_retention", "chip_sw_smc_cam_irq_test", "chip_sw_smc_ctrl_test", "chip_sw_smc_env_test", @@ -2139,6 +2145,7 @@ "chip_sw_flash_ctrl_access", "chip_sw_flash_ctrl_access_jitter_en", "chip_sw_flash_ctrl_access_jitter_en_reduced_freq", + "chip_sw_gpio", "chip_sw_hmac_enc", "chip_sw_hmac_smoketest", "chip_sw_i2c_host_tx_rx", @@ -2150,6 +2157,13 @@ "chip_sw_otbn_smoketest", "chip_sw_otp_ctrl_escalation", "chip_sw_otp_ctrl_smoketest", + "chip_sw_pwrmgr_b2b_sleep_reset_req", + "chip_sw_pwrmgr_deep_sleep_all_reset_reqs", + "chip_sw_pwrmgr_deep_sleep_power_glitch_reset", + "chip_sw_pwrmgr_normal_sleep_all_reset_reqs", + "chip_sw_pwrmgr_random_sleep_all_reset_reqs", + "chip_sw_pwrmgr_random_sleep_power_glitch_reset", + "chip_sw_pwrmgr_sleep_power_glitch_reset", "chip_sw_pwrmgr_sleep_sensor_ctrl_alert_wakeup", "chip_sw_rom_ctrl_integrity_check", "chip_sw_rstmgr_smoketest", @@ -2162,6 +2176,7 @@ "chip_sw_rv_timer_irq", "chip_sw_sensor_ctrl_alert", "chip_sw_sensor_ctrl_status", + "chip_sw_sleep_pin_retention", "chip_sw_smc_cam_irq_test", "chip_sw_smc_ctrl_test", "chip_sw_smc_env_test",
diff --git a/hw/top_matcha/dv/env/chip_env.core b/hw/top_matcha/dv/env/chip_env.core index 28fb4bf..8b229e1 100644 --- a/hw/top_matcha/dv/env/chip_env.core +++ b/hw/top_matcha/dv/env/chip_env.core
@@ -55,6 +55,7 @@ - seq_lib/chip_prim_tl_access_vseq.sv: {is_include_file: true} - seq_lib/chip_tap_straps_vseq.sv: {is_include_file: true} - seq_lib/chip_sw_base_vseq.sv: {is_include_file: true} + - seq_lib/chip_sw_smc_base_vseq.sv: {is_include_file: true} - seq_lib/chip_sw_uart_smoke_vseq.sv: {is_include_file: true} - seq_lib/chip_jtag_base_vseq.sv: {is_include_file: true} - seq_lib/chip_sw_alert_handler_entropy_vseq.sv: {is_include_file: true}
diff --git a/hw/top_matcha/dv/env/chip_if.sv b/hw/top_matcha/dv/env/chip_if.sv index 5b576bc..6663de3 100644 --- a/hw/top_matcha/dv/env/chip_if.sv +++ b/hw/top_matcha/dv/env/chip_if.sv
@@ -404,9 +404,9 @@ // hw/top_matcha/rtl/chip_matcha_verilator.sv and // sw/device/lib/testing/pinmux_testutils.c pins_if #(.Width(NUM_GPIOS), .PullStrength("Weak")) gpios_if( - .pins({mios[top_matcha_pkg::MioPadIor10], mios[top_matcha_pkg::MioPadIoc8], + .pins({mios[top_matcha_pkg::MioPadIor10], mios[top_matcha_pkg::MioPadIod1], mios[top_matcha_pkg::MioPadIor7], mios[top_matcha_pkg::MioPadIor6], - mios[top_matcha_pkg::MioPadIoc5], mios[top_matcha_pkg::MioPadIoc9], + mios[top_matcha_pkg::MioPadIod0], mios[top_matcha_pkg::MioPadIoc9], mios[top_matcha_pkg::MioPadIoc7], mios[top_matcha_pkg::MioPadIoc2], mios[top_matcha_pkg::MioPadIoc1], mios[top_matcha_pkg::MioPadIoc0], mios[top_matcha_pkg::MioPadIoc6], mios[top_matcha_pkg::MioPadIob12],
diff --git a/hw/top_matcha/dv/env/seq_lib/chip_sw_base_vseq.sv b/hw/top_matcha/dv/env/seq_lib/chip_sw_base_vseq.sv index ad8fdc2..f2a74c4 100644 --- a/hw/top_matcha/dv/env/seq_lib/chip_sw_base_vseq.sv +++ b/hw/top_matcha/dv/env/seq_lib/chip_sw_base_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 @@ -58,7 +59,6 @@ `uvm_info(`gfn, "Starting cpu_init", UVM_MEDIUM) // Initialize the sw logger interface. - // SEC foreach (cfg.sw_images[i]) begin if (i inside {SwTypeRom, SwTypeDebug, SwTypeTestSlotA, SwTypeTestSlotB}) begin cfg.sw_logger_vif.add_sw_log_db(cfg.sw_images[i]); @@ -67,19 +67,9 @@ cfg.sw_logger_vif.sw_log_addr = SW_DV_LOG_ADDR; cfg.sw_logger_vif.write_sw_logs_to_file = cfg.write_sw_logs_to_file; cfg.sw_logger_vif.ready(); - // SMC - foreach (cfg.sw_images[i]) begin - if (i inside {SwTypeSmc}) begin - cfg.sw_smc_logger_vif.add_sw_log_db(cfg.sw_images[i]); - end - end - cfg.sw_smc_logger_vif.sw_log_addr = SW_DV_SMC_LOG_ADDR; - cfg.sw_smc_logger_vif.write_sw_logs_to_file = cfg.write_sw_logs_to_file; - cfg.sw_smc_logger_vif.ready(); // Initialize the sw test status. - cfg.sw_test_status_vif.sw_test_status_addr = SW_DV_TEST_STATUS_ADDR; - cfg.sw_smc_test_status_vif.sw_test_status_addr = SW_DV_SMC_TEST_STATUS_ADDR; + cfg.sw_test_status_vif.sw_test_status_addr = SW_DV_TEST_STATUS_ADDR; `uvm_info(`gfn, "Initializing SRAMs", UVM_MEDIUM) @@ -129,11 +119,6 @@ cfg.mem_bkdr_util_h[FlashBank1Data].load_mem_from_file( {cfg.sw_images[SwTypeTestSlotB], ".64.scr.vmem"}); end - // SMC RAM sw imsage load - if (cfg.sw_images.exists(SwTypeSmc)) begin - cfg.mem_bkdr_util_h[Smc_ram].load_mem_from_file( - {cfg.sw_images[SwTypeSmc], ".32.vmem"}); - end config_jitter(); @@ -247,7 +232,7 @@ fork begin: isolation_thread fork - wait (cfg.sw_test_status_vif.sw_test_done || cfg.sw_smc_test_status_vif.sw_test_done); + wait (cfg.sw_test_status_vif.sw_test_done); #(cfg.sw_test_timeout_ns * 1ns); join_any disable fork; @@ -258,24 +243,15 @@ // Print pass / fail message to the log. virtual function void log_sw_test_status(); - if(cfg.sw_test_status_vif.sw_test_done || cfg.sw_smc_test_status_vif.sw_test_done) begin - if(cfg.sw_test_status_vif.sw_test_done) begin - case (cfg.sw_test_status_vif.sw_test_status) - SwTestStatusPassed: `uvm_info(`gfn, "[SEC] SW TEST PASSED!", UVM_LOW) - SwTestStatusFailed: `uvm_error(`gfn, "[SEC] SW TEST FAILED!") - endcase - end - if(cfg.sw_smc_test_status_vif.sw_test_done) begin - case (cfg.sw_smc_test_status_vif.sw_test_status) - SwTestStatusPassed: `uvm_info(`gfn, "[SMC] SW TEST PASSED!", UVM_LOW) - SwTestStatusFailed: `uvm_error(`gfn, "[SMC] SW TEST FAILED!") - endcase - end - end - else begin + case (cfg.sw_test_status_vif.sw_test_status) + SwTestStatusPassed: `uvm_info(`gfn, "SW TEST PASSED!", UVM_LOW) + SwTestStatusFailed: `uvm_error(`gfn, "SW TEST FAILED!") + default: begin + // If the SW test has not reached the passed / failed state, then it timed out. `uvm_error(`gfn, $sformatf("SW TEST TIMED OUT. STATE: %0s, TIMEOUT = %0d ns\n", - cfg.sw_smc_test_status_vif.sw_test_status.name(), cfg.sw_test_timeout_ns)) - end + cfg.sw_test_status_vif.sw_test_status.name(), cfg.sw_test_timeout_ns)) + end + endcase endfunction // Configure the provided spi_agent_cfg to use flash mode, and add the
diff --git a/hw/top_matcha/dv/env/seq_lib/chip_sw_gpio_vseq.sv b/hw/top_matcha/dv/env/seq_lib/chip_sw_gpio_vseq.sv index c6266ca..e6a5ddc 100644 --- a/hw/top_matcha/dv/env/seq_lib/chip_sw_gpio_vseq.sv +++ b/hw/top_matcha/dv/env/seq_lib/chip_sw_gpio_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 @@ -20,6 +21,7 @@ gpio_output_test(); // Run the GPIO input tests. + cfg.chip_vif.gpios_if.disconnect(); gpio_input_test(); endtask
diff --git a/hw/top_matcha/dv/env/seq_lib/chip_sw_smc_base_vseq.sv b/hw/top_matcha/dv/env/seq_lib/chip_sw_smc_base_vseq.sv new file mode 100644 index 0000000..612c3f2 --- /dev/null +++ b/hw/top_matcha/dv/env/seq_lib/chip_sw_smc_base_vseq.sv
@@ -0,0 +1,69 @@ +// 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 + +class chip_sw_smc_base_vseq extends chip_sw_base_vseq; + `uvm_object_utils(chip_sw_smc_base_vseq) + + `uvm_object_new + + virtual task cpu_init(); + super.cpu_init(); + + `uvm_info(`gfn, "Starting SMC cpu_init", UVM_MEDIUM) + + foreach (cfg.sw_images[i]) begin + if (i inside {SwTypeSmc}) begin + cfg.sw_smc_logger_vif.add_sw_log_db(cfg.sw_images[i]); + end + end + cfg.sw_smc_logger_vif.sw_log_addr = SW_DV_SMC_LOG_ADDR; + cfg.sw_smc_logger_vif.write_sw_logs_to_file = cfg.write_sw_logs_to_file; + cfg.sw_smc_logger_vif.ready(); + + // Initialize the sw test status. + cfg.sw_smc_test_status_vif.sw_test_status_addr = SW_DV_SMC_TEST_STATUS_ADDR; + + // SMC RAM sw image load + if (cfg.sw_images.exists(SwTypeSmc)) begin + cfg.mem_bkdr_util_h[Smc_ram].load_mem_from_file( + {cfg.sw_images[SwTypeSmc], ".32.vmem"}); + end + + `uvm_info(`gfn, "SMC cpu_init completed", UVM_MEDIUM) + endtask + + virtual task body(); + cfg.sw_smc_test_status_vif.set_num_iterations(num_trans); + // Initialize the CPU to kick off the sw test. TODO: Should be called in pre_start() instead. + cpu_init(); + endtask + + virtual task wait_for_sw_test_done(); + `uvm_info(`gfn, "Waiting for the SW test to finish", UVM_MEDIUM) + fork + begin: isolation_thread + fork + wait (cfg.sw_smc_test_status_vif.sw_test_done); + #(cfg.sw_test_timeout_ns * 1ns); + join_any + disable fork; + log_sw_test_status(); + end: isolation_thread + join + endtask + + virtual function void log_sw_test_status(); + case (cfg.sw_smc_test_status_vif.sw_test_status) + SwTestStatusPassed: `uvm_info(`gfn, "SW TEST PASSED!", UVM_LOW) + SwTestStatusFailed: `uvm_error(`gfn, "SW TEST FAILED!") + default: begin + // If the SW test has not reached the passed / failed state, then it timed out. + `uvm_error(`gfn, $sformatf("SW TEST TIMED OUT. STATE: %0s, TIMEOUT = %0d ns\n", + cfg.sw_smc_test_status_vif.sw_test_status.name(), cfg.sw_test_timeout_ns)) + end + endcase + endfunction + +endclass
diff --git a/hw/top_matcha/dv/env/seq_lib/chip_vseq_list.sv b/hw/top_matcha/dv/env/seq_lib/chip_vseq_list.sv index ebe1a2b..3701ea8 100644 --- a/hw/top_matcha/dv/env/seq_lib/chip_vseq_list.sv +++ b/hw/top_matcha/dv/env/seq_lib/chip_vseq_list.sv
@@ -11,6 +11,7 @@ `include "chip_jtag_mem_vseq.sv" // This needs to be listed prior to all sequences that derive from it. `include "chip_sw_base_vseq.sv" +`include "chip_sw_smc_base_vseq.sv" `include "chip_sw_uart_smoke_vseq.sv" `include "chip_jtag_base_vseq.sv" `include "chip_prim_tl_access_vseq.sv"
diff --git a/hw/top_matcha/ip/ast/ast.core b/hw/top_matcha/ip/ast/ast.core index 9211b6c..ac3dadc 100644 --- a/hw/top_matcha/ip/ast/ast.core +++ b/hw/top_matcha/ip/ast/ast.core
@@ -45,6 +45,8 @@ - rtl/sys_osc.sv - rtl/usb_clk.sv - rtl/usb_osc.sv + - rtl/audio_clk.sv + - rtl/audio_osc.sv - rtl/gfr_clk_mux2.sv - rtl/ast_clks_byp.sv - rtl/rglts_pdm_3p3v.sv
diff --git a/hw/top_matcha/ip/ast/rtl/ast.sv b/hw/top_matcha/ip/ast/rtl/ast.sv index 0c7c900..5f00c1c 100644 --- a/hw/top_matcha/ip/ast/rtl/ast.sv +++ b/hw/top_matcha/ip/ast/rtl/ast.sv
@@ -98,18 +98,22 @@ output logic [UsbCalibWidth-1:0] usb_io_pu_cal_o, // USB IO Pull-up Calibration Setting // smc source clock + input clk_src_smc_en_i, // SMC Source Clock Enable output logic clk_src_smc_o, // SMC Source Clock output logic clk_src_smc_val_o, // SMC Source Clock Valid // ml source clock + input clk_src_ml_en_i, // ML Source Clock Enable output logic clk_src_ml_o, // ML Source Clock output logic clk_src_ml_val_o, // ML Source Clock Valid // video source clock + input clk_src_video_en_i, // VideO Source Clock Enable output logic clk_src_video_o, // Video Source Clock output logic clk_src_video_val_o, // Video Source Clock Valid // audio source clock + input clk_src_audio_en_i, // AUDIO Source Clock Enable output logic clk_src_audio_o, // audio Source Clock output logic clk_src_audio_val_o, // audio Source Clock Valid @@ -518,6 +522,36 @@ /////////////////////////////////////// +// AUDIO Clock (Always ON) +/////////////////////////////////////// +logic rst_audio_clk_n, clk_audio_pd_n; +logic clk_src_audio_en, clk_osc_audio, clk_osc_audio_val; + +assign rst_audio_clk_n = vcmain_pok_por && vcc_pok; +assign clk_audio_pd_n = scan_mode || !deep_sleep; + +`ifdef AST_BYPASS_CLK +logic clk_audio_ext; +assign clk_audio_ext = clk_osc_byp_i.audio; +`endif + +assign clk_src_audio_en = clk_src_audio_en_i; + +audio_clk u_audio_clk ( + .vcore_pok_h_i ( vcaon_pok_h ), + .clk_audio_pd_ni ( clk_audio_pd_n ), + .rst_audio_clk_ni ( rst_audio_clk_n ), + .clk_src_audio_en_i ( clk_src_audio_en ), + .scan_mode_i ( scan_mode ), + .audio_osc_cal_i ( sys_io_osc_cal ), +`ifdef AST_BYPASS_CLK + .clk_audio_ext_i ( clk_audio_ext ), +`endif + .clk_src_audio_o ( clk_osc_audio ), + .clk_src_audio_val_o ( clk_osc_audio_val ) +); + +/////////////////////////////////////// // AST Clocks Bypass /////////////////////////////////////// logic clk_src_sys, clk_src_io, clk_src_usb, clk_src_aon; @@ -536,6 +570,9 @@ .clk_osc_usb_val_i ( clk_osc_usb_val ), .clk_osc_aon_i ( clk_osc_aon ), .clk_osc_aon_val_i ( clk_osc_aon_val ), + .clk_src_audio_en_i ( clk_src_audio_en_i ), + .clk_osc_audio_i ( clk_osc_audio ), + .clk_osc_audio_val_i ( clk_osc_audio_val ), .clk_ast_ext_i ( clk_ast_ext_i ), .io_clk_byp_req_i ( io_clk_byp_req_i ), .all_clk_byp_req_i ( all_clk_byp_req_i ), @@ -550,7 +587,9 @@ .clk_src_usb_o ( clk_src_usb ), .clk_src_usb_val_o ( clk_src_usb_val_o ), .clk_src_aon_o ( clk_src_aon ), - .clk_src_aon_val_o ( clk_src_aon_val_o ) + .clk_src_aon_val_o ( clk_src_aon_val_o ), + .clk_src_audio_o ( clk_src_audio ), + .clk_src_audio_val_o ( clk_src_audio_val_o ) ); // System source clock buffer @@ -590,47 +629,48 @@ ); -// TO-DO(pbf): Add PLL output for new clocks: smc, ml, video, audio -// For now, just use the same clock as clk_osc_ss - -assign clk_src_smc_val_o = 1'b1; -assign clk_src_ml_val_o = 1'b1; -assign clk_src_video_val_o = 1'b1; -assign clk_src_audio_val_o = 1'b1; +// TO-DO(VSI): Add PLL output for new clocks: smc, ml, video +// For DV test purpose as of now, smc/ml/video clock will just use the same clock as clk_src_syc. // SMC source clock buffer //////////////////////////////////////// prim_clock_buf #( .NoFpgaBuf ( 1'b1 ) ) u_clk_src_smc_buf ( - .clk_i ( clk_src_sys ), // TO-DO(pbf): use the sys_clk for now. Change to different clock late. + .clk_i ( clk_src_sys ), // TO-DO(VSI): use the sys_clk for now. Change to SMC clock late. .clk_o ( clk_src_smc_o ) ); +assign clk_src_smc_val_o = clk_src_sys_val_o; + // ML source clock buffer //////////////////////////////////////// prim_clock_buf #( .NoFpgaBuf ( 1'b1 ) ) u_clk_src_ml_buf ( - .clk_i ( clk_src_sys ), // TO-DO(pbf):use the sys_clk for now. Change to different clock late. + .clk_i ( clk_src_sys ), // TO-DO(VSI):use the sys_clk for now. Change to ML clock late. .clk_o ( clk_src_ml_o ) ); +assign clk_src_ml_val_o = clk_src_sys_val_o; + // video source clock buffer //////////////////////////////////////// prim_clock_buf #( .NoFpgaBuf ( 1'b1 ) ) u_clk_src_video_buf ( - .clk_i ( clk_src_sys ), // TO-DO(pbf):use the sys_clk for now. Change to different clock late. + .clk_i ( clk_src_sys ), // TO-DO(VSI):use the sys_clk for now. Change to video clock late. .clk_o ( clk_src_video_o ) ); +assign clk_src_video_val_o = clk_src_sys_val_o; + // audio source clock buffer //////////////////////////////////////// prim_clock_buf #( .NoFpgaBuf ( 1'b1 ) ) u_clk_src_audio_buf ( - .clk_i ( clk_src_usb ), // TO-DO(pbf): use 48Mhz usb clock as audio clock for FPGA for now. + .clk_i ( clk_src_audio ), .clk_o ( clk_src_audio_o ) );
diff --git a/hw/top_matcha/ip/ast/rtl/ast_clks_byp.sv b/hw/top_matcha/ip/ast/rtl/ast_clks_byp.sv index f7d6c0e..f21c774 100644 --- a/hw/top_matcha/ip/ast/rtl/ast_clks_byp.sv +++ b/hw/top_matcha/ip/ast/rtl/ast_clks_byp.sv
@@ -26,6 +26,9 @@ input clk_osc_usb_val_i, // USB Oscillator Clock Valid input clk_osc_aon_i, // AON Oscillator Clock input clk_osc_aon_val_i, // AON Oscillator Clock Valid + input clk_src_audio_en_i, // IO Source Clock Enable + input clk_osc_audio_i, // AUDIO Oscillator Clock + input clk_osc_audio_val_i, // AUDIO Oscillator Clock Valid input clk_ast_ext_i, // External Clock input prim_mubi_pkg::mubi4_t io_clk_byp_req_i, // External IO clock mux for OTP bootstrap input prim_mubi_pkg::mubi4_t all_clk_byp_req_i, // External all clock mux override @@ -40,7 +43,9 @@ output logic clk_src_usb_o, // USB Source Clock output logic clk_src_usb_val_o, // USB Source Clock Valid output logic clk_src_aon_o, // AON Source Clock - output logic clk_src_aon_val_o // AON Source Clock Valid + output logic clk_src_aon_val_o, // AON Source Clock Valid + output logic clk_src_audio_o, // AON Source Clock + output logic clk_src_audio_val_o // AON Source Clock Valid ); logic scan_mode_i, scan_reset_ni; @@ -267,7 +272,32 @@ .clk_o ( clk_ext_usb ) ); +// AUDIO External Clock Enable +//////////////////////////////////////// +logic clk_ext_audio, clk_ext_audio_en, clk_ext_audio_val; +logic clk_src_audio_en; +prim_flop_2sync #( + .Width ( 1 ), + .ResetValue ( 1'b0 ) +) u_no_scan_clk_src_audio_en_sync ( + .clk_i ( clk_ext ), + .rst_ni ( rst_aon_exda_n ), + .d_i ( clk_src_audio_en_i ), + .q_o ( clk_src_audio_en ) +); + +assign clk_ext_audio_en = deep_sleep_n && clk_src_audio_en; +assign clk_ext_audio_val = clk_ext_audio_en; + +prim_clock_gating #( + .NoFpgaGate ( 1'b1) +) u_clk_ext_audio_ckgt ( + .clk_i ( clk_ext ), + .en_i ( clk_ext_audio_en ), + .test_en_i ( scan_mode_i ), + .clk_o ( clk_ext_audio ) +); //////////////////////////////////////// // SW Bypass select logic //////////////////////////////////////// @@ -305,16 +335,17 @@ ); // Decode logic -logic ot_all_clk_byp, ot_sys_clk_byp, ot_io_clk_byp, ot_usb_clk_byp, ot_aon_clk_byp; +logic ot_all_clk_byp, ot_sys_clk_byp, ot_io_clk_byp, ot_usb_clk_byp, ot_aon_clk_byp, ot_audio_clk_byp; prim_mubi4_dec u_all_byp_sel ( .mubi_i ( ot_all_clk_byp_req ), .mubi_dec_o ( ot_all_clk_byp ) ); prim_mubi4_dec u_sys_byp_sel ( .mubi_i ( ot_all_clk_byp_req ), .mubi_dec_o ( ot_sys_clk_byp ) ); prim_mubi4_dec u_io_byp_sel ( .mubi_i ( ot_io_clk_byp_req ), .mubi_dec_o ( ot_io_clk_byp ) ); prim_mubi4_dec u_usb_byp_sel ( .mubi_i ( ot_all_clk_byp_req ), .mubi_dec_o ( ot_usb_clk_byp ) ); prim_mubi4_dec u_aon_byp_sel ( .mubi_i ( ot_all_clk_byp_req ), .mubi_dec_o ( ot_aon_clk_byp ) ); +prim_mubi4_dec u_audio_byp_sel ( .mubi_i ( ot_all_clk_byp_req ), .mubi_dec_o ( ot_audio_clk_byp ) ); // De-Glitch selects (decode "noise") -logic sw_sys_clk_byp, sw_usb_clk_byp, sw_aon_clk_byp, sw_exfr_is_96m; +logic sw_sys_clk_byp, sw_usb_clk_byp, sw_aon_clk_byp, sw_exfr_is_96m, sw_audio_clk_byp; prim_flop #( .Width ( 1 ), @@ -376,6 +407,16 @@ .q_o ( sw_exfr_is_96m ) ); +prim_flop #( + .Width ( 1 ), + .ResetValue ( 1'b0 ) +) u_sw_audio_clk_byp_dgl ( + .clk_i ( clk_aon ), + .rst_ni ( rst_aon_n ), + .d_i ( ot_audio_clk_byp ), + .q_o ( sw_audio_clk_byp ) +); + logic sys_clk_byp; assign sys_clk_byp = sw_sys_clk_byp; @@ -408,9 +449,13 @@ assign extfreq_is_96m = sw_exfr_is_96m; +logic audio_clk_byp; + +assign audio_clk_byp = sw_audio_clk_byp; + // Block changes during scan mode //////////////////////////////////////// -logic sys_clk_byp_sel, io_clk_byp_sel, usb_clk_byp_sel, aon_clk_byp_sel; +logic sys_clk_byp_sel, io_clk_byp_sel, usb_clk_byp_sel, aon_clk_byp_sel, audio_clk_byp_sel; always_latch begin if ( !scan_mode_i ) begin @@ -419,6 +464,7 @@ usb_clk_byp_sel = usb_clk_byp; aon_clk_byp_sel = aon_clk_byp; ext_freq_is_96m = extfreq_is_96m; + audio_clk_byp_sel = audio_clk_byp; end end @@ -426,8 +472,8 @@ //////////////////////////////////////// // Clocks Bypass Muxes //////////////////////////////////////// -logic sys_clk_osc_en, io_clk_osc_en, usb_clk_osc_en, aon_clk_osc_en; -logic sys_clk_byp_en, io_clk_byp_en, usb_clk_byp_en, aon_clk_byp_en; +logic sys_clk_osc_en, io_clk_osc_en, usb_clk_osc_en, aon_clk_osc_en, audio_clk_osc_en; +logic sys_clk_byp_en, io_clk_byp_en, usb_clk_byp_en, aon_clk_byp_en, audio_clk_byp_en; logic rst_clk_osc_n, rst_clk_ext_n; assign rst_clk_osc_n = vcaon_pok; @@ -455,6 +501,7 @@ logic rst_clk_osc_sys_n, rst_clk_ext_sys_n, rst_clk_osc_io_n, rst_clk_ext_io_n; logic rst_clk_osc_usb_n, rst_clk_ext_usb_n, rst_clk_osc_aon_n, rst_clk_ext_aon_n; +logic rst_clk_osc_audio_n, rst_clk_ext_audio_n; prim_buf u_rst_clk_osc_sys ( .in_i ( rst_clk_osc_n ), @@ -496,6 +543,16 @@ .out_o ( rst_clk_ext_aon_n ) ); +prim_buf u_rst_clk_osc_audio ( + .in_i ( rst_clk_osc_n ), + .out_o ( rst_clk_osc_audio_n ) +); + +prim_buf u_rst_clk_ext_audio ( + .in_i ( rst_clk_ext_n ), + .out_o ( rst_clk_ext_audio_n ) +); + // SYS Clock Bypass Mux //////////////////////////////////////// gfr_clk_mux2 u_clk_src_sys_sel ( @@ -560,6 +617,22 @@ .clk_o ( clk_src_aon_o ) ); +// AUDIO Clock Bypass Mux +//////////////////////////////////////// +gfr_clk_mux2 u_clk_src_audio_sel ( + .clk_osc_i ( clk_osc_audio_i ), + .clk_osc_val_i ( clk_osc_audio_val_i ), + .rst_clk_osc_ni ( rst_clk_osc_audio_n ), + .clk_ext_i ( clk_ext_audio ), + .clk_ext_val_i ( clk_ext_audio_val ), + .rst_clk_ext_ni ( rst_clk_ext_audio_n ), + .ext_sel_i ( audio_clk_byp_sel ), + .clk_osc_en_o ( audio_clk_osc_en ), + .clk_ext_en_o ( audio_clk_byp_en ), + .clk_val_o ( clk_src_audio_val_o ), + .clk_o ( clk_src_audio_o ) +); + // rst_aon_n deasset to io clock //////////////////////////////////////// logic rst_aon_n_ioda, rst_aon_ioda_n; @@ -585,7 +658,7 @@ all_clks_byp_en_src <= 1'b0; end else begin all_clks_byp_en_src <= sw_all_clk_byp && sys_clk_byp_en && io_clk_byp_en && - usb_clk_byp_en && aon_clk_byp_en; + usb_clk_byp_en && aon_clk_byp_en && audio_clk_byp_en; end end
diff --git a/hw/top_matcha/ip/ast/rtl/audio_clk.sv b/hw/top_matcha/ip/ast/rtl/audio_clk.sv new file mode 100644 index 0000000..4ad7d32 --- /dev/null +++ b/hw/top_matcha/ip/ast/rtl/audio_clk.sv
@@ -0,0 +1,63 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +//############################################################################ +// *Name: audio_clk +// *Module Description: AUDIO Clock +//############################################################################ + +module audio_clk ( + input vcore_pok_h_i, // VCORE POK @3.3V (for OSC) + input clk_audio_pd_ni, // IO Clock Power-down + input rst_audio_clk_ni, // IO Clock Logic reset + input clk_src_audio_en_i, // IO Source Clock Enable + input scan_mode_i, // Scan Mode + input audio_osc_cal_i, // IO Oscillator Calibrated +`ifdef AST_BYPASS_CLK + input clk_audio_ext_i, // FPGA/VERILATOR Clock input +`endif + output logic clk_src_audio_o, // IO Source Clock + output logic clk_src_audio_val_o // IO Source Clock Valid +); + +logic clk, osc_en, audio_clk_en; + +assign osc_en = (clk_src_audio_en_i && clk_audio_pd_ni && rst_audio_clk_ni); +assign audio_clk_en = scan_mode_i || osc_en; + +// Clock Oscilator +/////////////////////////////////////// +audio_osc u_audio_osc ( + .vcore_pok_h_i ( vcore_pok_h_i ), + .audio_en_i ( audio_clk_en ), + .audio_osc_cal_i ( audio_osc_cal_i ), +`ifdef AST_BYPASS_CLK + .clk_audio_ext_i ( clk_audio_ext_i ), +`endif + .audio_clk_o ( clk ) +); // of u_audio_osc + +// Clock & Valid +/////////////////////////////////////// +prim_clock_buf #( + .NoFpgaBuf ( 1'b1 ) +) u_clk_audio_buf( + .clk_i ( clk ), + .clk_o ( clk_src_audio_o ) +); + +// 2-stage de-assertion +logic rst_val_n; +assign rst_val_n = audio_clk_en; + +prim_flop_2sync #( + .Width ( 1 ), + .ResetValue ( 1'b0 ) +) u_no_scan_val_sync ( + .clk_i ( clk_src_audio_o ), + .rst_ni ( rst_val_n ), + .d_i ( 1'b1 ), + .q_o ( clk_src_audio_val_o ) +); + +endmodule : audio_clk
diff --git a/hw/top_matcha/ip/ast/rtl/audio_osc.sv b/hw/top_matcha/ip/ast/rtl/audio_osc.sv new file mode 100644 index 0000000..c24f4e7 --- /dev/null +++ b/hw/top_matcha/ip/ast/rtl/audio_osc.sv
@@ -0,0 +1,131 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +//############################################################################ +// *Name: audio_osc +// *Module Description: AUDIO Clock Oscilator +//############################################################################ + +module audio_osc ( + input vcore_pok_h_i, // VCORE POK @3.3V + input audio_en_i, // IO Source Clock Enable + input audio_osc_cal_i, // IO Oscillator Calibrated +`ifdef AST_BYPASS_CLK + input clk_audio_ext_i, // FPGA/VERILATOR Clock input +`endif + output logic audio_clk_o // IO Clock Output +); + +`ifndef AST_BYPASS_CLK +`ifndef SYNTHESIS +// Behavioral Model +//////////////////////////////////////// +timeunit 1ns / 1ps; + +real CLK_PERIOD; + +reg init_start; +initial init_start = 1'b0; + +initial begin + #1; + init_start = 1'b1; + #1; + $display("\n%m: IO Clock Power-up Frequency: %0d Hz", $rtoi(10**9/CLK_PERIOD)); +end + +// Enable 5us RC Delay on rise +wire en_osc_re_buf, en_osc_re; +buf #(ast_bhv_pkg::IO_EN_RDLY, 0) b0 (en_osc_re_buf, (vcore_pok_h_i && audio_en_i)); +assign en_osc_re = en_osc_re_buf && init_start; + + +// Clock Oscillator +//////////////////////////////////////// +real CalIoClkPeriod, UncIoClkPeriod, IoClkPeriod; + +initial CalIoClkPeriod = $itor( 1000000/48 ); // ~20833.333333ps (48MHz) +initial UncIoClkPeriod = $itor( $urandom_range(55555, 25000) ); // 55555-25000ps (18-40MHz) + +assign IoClkPeriod = (audio_osc_cal_i && init_start) ? CalIoClkPeriod : UncIoClkPeriod; +assign CLK_PERIOD = IoClkPeriod/1000; + +// Free running oscillator +reg clk_osc; +initial clk_osc = 1'b1; + +always begin + #(CLK_PERIOD/2) clk_osc = ~clk_osc; +end + +logic en_osc; + +// HDL Clock Gate +logic en_clk, clk; + +always_latch begin + if ( !clk_osc ) en_clk = en_osc; +end + +assign clk = clk_osc && en_clk; +`else // of SYNTHESIS +// SYNTHESIS/LINTER +/////////////////////////////////////// +logic en_osc_re; +assign en_osc_re = vcore_pok_h_i && audio_en_i; + +logic clk, en_osc; +assign clk = 1'b0; +`endif // of SYNTHESIS +`else // of AST_BYPASS_CLK +// VERILATOR/FPGA +/////////////////////////////////////// +logic en_osc_re; +assign en_osc_re = vcore_pok_h_i && audio_en_i; + +// Clock Oscillator +//////////////////////////////////////// +logic clk, en_osc; + +prim_clock_gating #( + .NoFpgaGate ( 1'b1 ) +) u_clk_ckgt ( + .clk_i ( clk_audio_ext_i ), + .en_i ( en_osc ), + .test_en_i ( 1'b0 ), + .clk_o ( clk ) +); +`endif + +logic en_osc_fe; + +// Syncronize en_osc to clk FE for glitch free disable +always_ff @( negedge clk, negedge vcore_pok_h_i ) begin + if ( !vcore_pok_h_i ) begin + en_osc_fe <= 1'b0; + end else begin + en_osc_fe <= en_osc_re; + end +end + +assign en_osc = en_osc_re || en_osc_fe; // EN -> 1 || EN -> 0 + +// Clock Output Buffer +//////////////////////////////////////// +prim_clock_buf #( + .NoFpgaBuf ( 1'b1 ) +) u_buf ( + .clk_i ( clk ), + .clk_o ( audio_clk_o ) +); + + +`ifdef SYNTHESIS +///////////////////////// +// Unused Signals +///////////////////////// +logic unused_sigs; +assign unused_sigs = ^{ audio_osc_cal_i }; +`endif + +endmodule : audio_osc
diff --git a/hw/top_matcha/ip/i2s/rtl/i2s_rx.sv b/hw/top_matcha/ip/i2s/rtl/i2s_rx.sv index 74ad7a3..d62b762 100644 --- a/hw/top_matcha/ip/i2s/rtl/i2s_rx.sv +++ b/hw/top_matcha/ip/i2s/rtl/i2s_rx.sv
@@ -88,12 +88,13 @@ end end - // Bits were clocked on the line falling edge of clock. Latch data in on rising. + // Clock in data in on rising edge. always_ff @(posedge sclk_o or negedge rst_ni) begin if (!rst_ni) begin shift_reg <= '0; + end else begin + shift_reg <= {shift_reg[WordWidth-2:0], serial_data_i}; end - shift_reg <= {shift_reg[WordWidth-2:0], serial_data_i}; end endmodule
diff --git a/hw/top_matcha/ip/smc/rtl/smc_core.sv b/hw/top_matcha/ip/smc/rtl/smc_core.sv index 43e5242..7748ffc 100644 --- a/hw/top_matcha/ip/smc/rtl/smc_core.sv +++ b/hw/top_matcha/ip/smc/rtl/smc_core.sv
@@ -949,7 +949,6 @@ .mmu_data_rdata_o ( mmu_data_rdata ), .lsu_req_i ( lsu_req ), - .lsu_req_done_i ( lsu_req_done ), .lsu_req_in_dec_i ( lsu_req_in_dec ), // General Control Signals
diff --git a/hw/top_matcha/ip/smc/rtl/smc_mmu.sv b/hw/top_matcha/ip/smc/rtl/smc_mmu.sv index ca56ac8..69880b4 100644 --- a/hw/top_matcha/ip/smc/rtl/smc_mmu.sv +++ b/hw/top_matcha/ip/smc/rtl/smc_mmu.sv
@@ -49,7 +49,6 @@ output logic [31:0] mmu_data_rdata_o, input logic lsu_req_i, - input logic lsu_req_done_i, // used to ensure we don't store to dmem twice after a ptw finishes input logic lsu_req_in_dec_i, // General Control Signals @@ -248,7 +247,7 @@ assign paging_en_lsu = satp_i.mode & (priv_lvl_lsu_i != PRIV_LVL_M); // Categorize atomic RMW ops and stores as writes for pte permissions - assign is_write = (mmu_data_we_i != LOAD) ? 1'b1 : 1'b0; + assign is_write = mmu_data_we_i != LOAD; // Check page access errors based on privilege mode and mstatus bits only assign dmem_access_error = @@ -367,7 +366,7 @@ data_addr_o = dtlb_superpage ? {dtlb_pte_content.ppn[19:10], mmu_data_addr_i[21:0]} : {dtlb_pte_content.ppn[19:0], mmu_data_addr_i[11:0]}; data_req_o = mmu_data_req_i; - data_we = is_write & (ptw_finish_lsu_dec_q | lsu_req_done_i); + data_we = is_write; data_be_o = mmu_data_be_i; data_wdata_o = mmu_data_wdata_i;
diff --git a/hw/top_matcha/rtl/autogen/chip_matcha_asic.sv b/hw/top_matcha/rtl/autogen/chip_matcha_asic.sv index 2475bdd..9f4cb53 100644 --- a/hw/top_matcha/rtl/autogen/chip_matcha_asic.sv +++ b/hw/top_matcha/rtl/autogen/chip_matcha_asic.sv
@@ -1036,15 +1036,19 @@ .clk_src_usb_o ( ast_base_clks.clk_usb ), .clk_src_usb_val_o ( ast_base_pwr.usb_clk_val ), // smc source clock + .clk_src_smc_en_i ( base_ast_pwr.smc_clk_en ), .clk_src_smc_o ( ast_base_clks.clk_smc ), .clk_src_smc_val_o ( ast_base_pwr.smc_clk_val), // ml source clock + .clk_src_ml_en_i ( base_ast_pwr.ml_clk_en ), .clk_src_ml_o ( ast_base_clks.clk_ml ), .clk_src_ml_val_o ( ast_base_pwr.ml_clk_val), // video source clock + .clk_src_video_en_i ( base_ast_pwr.video_clk_en ), .clk_src_video_o ( ast_base_clks.clk_video ), .clk_src_video_val_o ( ast_base_pwr.video_clk_val), // audio source clock + .clk_src_audio_en_i ( base_ast_pwr.audio_clk_en ), .clk_src_audio_o ( ast_base_clks.clk_audio ), .clk_src_audio_val_o ( ast_base_pwr.audio_clk_val), // adc
diff --git a/hw/top_matcha/rtl/autogen/chip_matcha_nexus.sv b/hw/top_matcha/rtl/autogen/chip_matcha_nexus.sv index fad1369..f8fb1dd 100644 --- a/hw/top_matcha/rtl/autogen/chip_matcha_nexus.sv +++ b/hw/top_matcha/rtl/autogen/chip_matcha_nexus.sv
@@ -824,15 +824,19 @@ .clk_src_usb_o ( ast_base_clks.clk_usb ), .clk_src_usb_val_o ( ast_base_pwr.usb_clk_val ), // smc source clock + .clk_src_smc_en_i ( base_ast_pwr.smc_clk_en ), .clk_src_smc_o ( ast_base_clks.clk_smc ), .clk_src_smc_val_o ( ast_base_pwr.smc_clk_val), // ml source clock + .clk_src_ml_en_i ( base_ast_pwr.ml_clk_en ), .clk_src_ml_o ( ast_base_clks.clk_ml ), .clk_src_ml_val_o ( ast_base_pwr.ml_clk_val), // video source clock + .clk_src_video_en_i ( base_ast_pwr.video_clk_en ), .clk_src_video_o ( ast_base_clks.clk_video ), .clk_src_video_val_o ( ast_base_pwr.video_clk_val), // audio source clock + .clk_src_audio_en_i ( base_ast_pwr.audio_clk_en ), .clk_src_audio_o ( ast_base_clks.clk_audio ), .clk_src_audio_val_o ( ast_base_pwr.audio_clk_val), // adc
diff --git a/hw/top_matcha/rtl/chip_matcha_verilator.sv b/hw/top_matcha/rtl/chip_matcha_verilator.sv index d66f69b..8bee784 100644 --- a/hw/top_matcha/rtl/chip_matcha_verilator.sv +++ b/hw/top_matcha/rtl/chip_matcha_verilator.sv
@@ -486,15 +486,19 @@ .clk_src_usb_o ( ast_base_clks.clk_usb ), .clk_src_usb_val_o ( ast_base_pwr.usb_clk_val ), // smc source clock + .clk_src_smc_en_i ( base_ast_pwr.smc_clk_en ), .clk_src_smc_o ( ast_base_clks.clk_smc ), .clk_src_smc_val_o ( ast_base_pwr.smc_clk_val), // ml source clock + .clk_src_ml_en_i ( base_ast_pwr.ml_clk_en ), .clk_src_ml_o ( ast_base_clks.clk_ml ), .clk_src_ml_val_o ( ast_base_pwr.ml_clk_val), // video source clock + .clk_src_video_en_i ( base_ast_pwr.video_clk_en ), .clk_src_video_o ( ast_base_clks.clk_video ), .clk_src_video_val_o ( ast_base_pwr.video_clk_val), // audio source clock + .clk_src_audio_en_i ( base_ast_pwr.audio_clk_en ), .clk_src_audio_o ( ast_base_clks.clk_audio ), .clk_src_audio_val_o ( ast_base_pwr.audio_clk_val), // adc
diff --git a/sw/device/lib/testing/pinmux_testutils.c b/sw/device/lib/testing/pinmux_testutils.c index ea18a08..d71a23e 100644 --- a/sw/device/lib/testing/pinmux_testutils.c +++ b/sw/device/lib/testing/pinmux_testutils.c
@@ -17,41 +17,41 @@ // hw/top_matcha/rtl/chip_matcha_verilator.sv and // hw/top_matcha/dv/env/chip_if.sv const dif_pinmux_index_t kPinmuxTestutilsGpioInselPins[kDifGpioNumPins] = { - kTopMatchaPinmuxInselIoa0, kTopMatchaPinmuxInselIoa1, - kTopMatchaPinmuxInselIoa2, kTopMatchaPinmuxInselIoa3, - kTopMatchaPinmuxInselIoa4, kTopMatchaPinmuxInselIoa5, - kTopMatchaPinmuxInselIoa6, kTopMatchaPinmuxInselIoa7, - kTopMatchaPinmuxInselIoa8, kTopMatchaPinmuxInselIob0, - kTopMatchaPinmuxInselIob1, kTopMatchaPinmuxInselIob2, - kTopMatchaPinmuxInselIob3, kTopMatchaPinmuxInselIob4, - kTopMatchaPinmuxInselIob5, kTopMatchaPinmuxInselIob6, - kTopMatchaPinmuxInselIob7, kTopMatchaPinmuxInselIob8, - kTopMatchaPinmuxInselIob10, kTopMatchaPinmuxInselIob11, - kTopMatchaPinmuxInselIob12, kTopMatchaPinmuxInselIoc6, - kTopMatchaPinmuxInselIoc0, kTopMatchaPinmuxInselIoc1, - kTopMatchaPinmuxInselIoc2, kTopMatchaPinmuxInselIoc7, - kTopMatchaPinmuxInselIoc9, kTopMatchaPinmuxInselIoc5, - kTopMatchaPinmuxInselIor6, kTopMatchaPinmuxInselIor7, - kTopMatchaPinmuxInselIoc8, kTopMatchaPinmuxInselIor10, + kTopMatchaPinmuxInselIoa0, kTopMatchaPinmuxInselIoa1, + kTopMatchaPinmuxInselIoa2, kTopMatchaPinmuxInselIoa3, + kTopMatchaPinmuxInselIoa4, kTopMatchaPinmuxInselIoa5, + kTopMatchaPinmuxInselIoa6, kTopMatchaPinmuxInselIoa7, + kTopMatchaPinmuxInselIoa8, kTopMatchaPinmuxInselIob0, + kTopMatchaPinmuxInselIob1, kTopMatchaPinmuxInselIob2, + kTopMatchaPinmuxInselIob3, kTopMatchaPinmuxInselIob4, + kTopMatchaPinmuxInselIob5, kTopMatchaPinmuxInselIob6, + kTopMatchaPinmuxInselIob7, kTopMatchaPinmuxInselIob8, + kTopMatchaPinmuxInselIob10, kTopMatchaPinmuxInselIob11, + kTopMatchaPinmuxInselIob12, kTopMatchaPinmuxInselIoc6, + kTopMatchaPinmuxInselIoc0, kTopMatchaPinmuxInselIoc1, + kTopMatchaPinmuxInselIoc2, kTopMatchaPinmuxInselIoc7, + kTopMatchaPinmuxInselIoc9, kTopMatchaPinmuxInselIod0, + kTopMatchaPinmuxInselIor6, kTopMatchaPinmuxInselIor7, + kTopMatchaPinmuxInselIod1, kTopMatchaPinmuxInselIor10, }; const dif_pinmux_index_t kPinmuxTestutilsGpioMioOutPins[kDifGpioNumPins] = { - kTopMatchaPinmuxMioOutIoa0, kTopMatchaPinmuxMioOutIoa1, - kTopMatchaPinmuxMioOutIoa2, kTopMatchaPinmuxMioOutIoa3, - kTopMatchaPinmuxMioOutIoa4, kTopMatchaPinmuxMioOutIoa5, - kTopMatchaPinmuxMioOutIoa6, kTopMatchaPinmuxMioOutIoa7, - kTopMatchaPinmuxMioOutIoa8, kTopMatchaPinmuxMioOutIob0, - kTopMatchaPinmuxMioOutIob1, kTopMatchaPinmuxMioOutIob2, - kTopMatchaPinmuxMioOutIob3, kTopMatchaPinmuxMioOutIob4, - kTopMatchaPinmuxMioOutIob5, kTopMatchaPinmuxMioOutIob6, - kTopMatchaPinmuxMioOutIob7, kTopMatchaPinmuxMioOutIob8, - kTopMatchaPinmuxMioOutIob10, kTopMatchaPinmuxMioOutIob11, - kTopMatchaPinmuxMioOutIob12, kTopMatchaPinmuxMioOutIoc6, - kTopMatchaPinmuxMioOutIoc0, kTopMatchaPinmuxMioOutIoc1, - kTopMatchaPinmuxMioOutIoc2, kTopMatchaPinmuxMioOutIoc7, - kTopMatchaPinmuxMioOutIoc9, kTopMatchaPinmuxMioOutIoc5, - kTopMatchaPinmuxMioOutIor6, kTopMatchaPinmuxMioOutIor7, - kTopMatchaPinmuxMioOutIoc8, kTopMatchaPinmuxMioOutIor10, + kTopMatchaPinmuxMioOutIoa0, kTopMatchaPinmuxMioOutIoa1, + kTopMatchaPinmuxMioOutIoa2, kTopMatchaPinmuxMioOutIoa3, + kTopMatchaPinmuxMioOutIoa4, kTopMatchaPinmuxMioOutIoa5, + kTopMatchaPinmuxMioOutIoa6, kTopMatchaPinmuxMioOutIoa7, + kTopMatchaPinmuxMioOutIoa8, kTopMatchaPinmuxMioOutIob0, + kTopMatchaPinmuxMioOutIob1, kTopMatchaPinmuxMioOutIob2, + kTopMatchaPinmuxMioOutIob3, kTopMatchaPinmuxMioOutIob4, + kTopMatchaPinmuxMioOutIob5, kTopMatchaPinmuxMioOutIob6, + kTopMatchaPinmuxMioOutIob7, kTopMatchaPinmuxMioOutIob8, + kTopMatchaPinmuxMioOutIob10, kTopMatchaPinmuxMioOutIob11, + kTopMatchaPinmuxMioOutIob12, kTopMatchaPinmuxMioOutIoc6, + kTopMatchaPinmuxMioOutIoc0, kTopMatchaPinmuxMioOutIoc1, + kTopMatchaPinmuxMioOutIoc2, kTopMatchaPinmuxMioOutIoc7, + kTopMatchaPinmuxMioOutIoc9, kTopMatchaPinmuxMioOutIod0, + kTopMatchaPinmuxMioOutIor6, kTopMatchaPinmuxMioOutIor7, + kTopMatchaPinmuxMioOutIod1, kTopMatchaPinmuxMioOutIor10, }; void pinmux_testutils_init(dif_pinmux_t *pinmux) { @@ -104,3 +104,5 @@ CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIoc11, kTopMatchaPinmuxOutselSmcUartTx)); } + +uint32_t pinmux_testutils_get_testable_gpios_mask(void) { return 0xffffffff; }
diff --git a/sw/device/lib/testing/pinmux_testutils.h b/sw/device/lib/testing/pinmux_testutils.h index 984b27f..657d6f0 100644 --- a/sw/device/lib/testing/pinmux_testutils.h +++ b/sw/device/lib/testing/pinmux_testutils.h
@@ -25,4 +25,12 @@ extern const dif_pinmux_index_t kPinmuxTestutilsGpioInselPins[kDifGpioNumPins]; extern const dif_pinmux_index_t kPinmuxTestutilsGpioMioOutPins[kDifGpioNumPins]; +/** + * Returns the mask of testable GPIO pins. + * + * Returns a simulation-device-specific mask that enables testing of only a + * subset of GPIOs depending on the IO allocation limitations. + */ +uint32_t pinmux_testutils_get_testable_gpios_mask(void); + #endif // MATCHA_SW_DEVICE_LIB_TESTING_PINMUX_TESTUTILS_H_
diff --git a/sw/device/tests/BUILD b/sw/device/tests/BUILD index 0bee4f2..48a45e5 100644 --- a/sw/device/tests/BUILD +++ b/sw/device/tests/BUILD
@@ -852,15 +852,13 @@ matcha_dv_test( name = "sensor_ctrl_wakeup_test", - srcs = ["@lowrisc_opentitan//sw/device/tests:sensor_ctrl_wakeup.c"], + srcs = ["sensor_ctrl_wakeup.c"], deps = [ - ":test_dv_lib_opentitan", - "//hw/top_matcha/ip/sensor_ctrl/data:sensor_ctrl_regs", + ":test_dv_lib", "//sw/device/lib/dif:rv_plic_sec", - "@lowrisc_opentitan//sw/device/lib/arch:device", + "//sw/device/lib/testing:isr_testutils", "@lowrisc_opentitan//sw/device/lib/dif:pwrmgr", "@lowrisc_opentitan//sw/device/lib/dif:sensor_ctrl", - "@lowrisc_opentitan//sw/device/lib/testing:isr_testutils", "@lowrisc_opentitan//sw/device/lib/testing:pwrmgr_testutils", "@lowrisc_opentitan//sw/device/lib/testing:rv_plic_testutils", ],
diff --git a/sw/device/tests/sensor_ctrl_wakeup.c b/sw/device/tests/sensor_ctrl_wakeup.c new file mode 100644 index 0000000..d1529b0 --- /dev/null +++ b/sw/device/tests/sensor_ctrl_wakeup.c
@@ -0,0 +1,133 @@ +// 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 "sensor_ctrl_regs.h" // Generated. +#include "sw/device/lib/base/mmio.h" +#include "sw/device/lib/dif/dif_pwrmgr.h" +#include "sw/device/lib/dif/dif_rv_plic.h" +#include "sw/device/lib/dif/dif_sensor_ctrl.h" +#include "sw/device/lib/runtime/ibex.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/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(); + +static dif_pwrmgr_t pwrmgr; +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}; + +static bool get_wakeup_status(void) { + dif_pwrmgr_request_sources_t wake_req = -1; + CHECK_DIF_OK(dif_pwrmgr_get_current_request_sources( + &pwrmgr, kDifPwrmgrReqTypeWakeup, &wake_req)); + return (wake_req > 0); +} + +/** + * 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_sensor_ctrl_t sensor_ctrl; + + // Enable global and external IRQ at Ibex. + irq_global_ctrl(true); + irq_external_ctrl(true); + + // Initialize the PLIC. + mmio_region_t plic_base_addr = + mmio_region_from_addr(TOP_MATCHA_RV_PLIC_BASE_ADDR); + CHECK_DIF_OK(dif_rv_plic_init(plic_base_addr, &plic)); + + // Initialize pwrmgr + CHECK_DIF_OK(dif_pwrmgr_init( + mmio_region_from_addr(TOP_MATCHA_PWRMGR_AON_BASE_ADDR), &pwrmgr)); + + // Initialize sensor_ctrl + CHECK_DIF_OK(dif_sensor_ctrl_init( + mmio_region_from_addr(TOP_MATCHA_SENSOR_CTRL_BASE_ADDR), &sensor_ctrl)); + + // 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)); + + // Capture the number of events to test + uint32_t sensor_ctrl_events = SENSOR_CTRL_PARAM_NUM_ALERT_EVENTS; + + dif_pwrmgr_domain_config_t sleep_config = + kDifPwrmgrDomainOptionMainPowerInLowPower; + + for (size_t i = 0; i < sensor_ctrl_events; ++i) { + LOG_INFO("Testing sensor_ctrl event %d", i); + + // Setup event trigger + CHECK_DIF_OK(dif_sensor_ctrl_set_ast_event_trigger(&sensor_ctrl, i, + kDifToggleEnabled)); + + // Normal sleep. + pwrmgr_testutils_enable_low_power(&pwrmgr, kDifPwrmgrWakeupRequestSourceSix, + sleep_config); + + // Enter low power mode. + LOG_INFO("Issue WFI to enter sleep"); + wait_for_interrupt(); + + // Wakeup from sleep. + LOG_INFO("Wake from sleep"); + + dif_sensor_ctrl_events_t events; + CHECK_DIF_OK(dif_sensor_ctrl_get_recov_events(&sensor_ctrl, &events)); + + if (events != (1 << i)) { + LOG_ERROR("Recoverable event 0x%x does not match expectation %d", events, + i); + } + + // clear event trigger + CHECK_DIF_OK(dif_sensor_ctrl_set_ast_event_trigger(&sensor_ctrl, i, + kDifToggleDisabled)); + + // since there is synchronization delay to trigger clearing and actual event + // de-assertion, clear and poll until it is finished before moving on + while (events) { + CHECK_DIF_OK(dif_sensor_ctrl_clear_recov_event(&sensor_ctrl, i)); + CHECK_DIF_OK(dif_sensor_ctrl_get_recov_events(&sensor_ctrl, &events)); + } + + // ensure the de-asserted events have cleared from the wakeup pipeline + // within 30us + IBEX_SPIN_FOR(!get_wakeup_status(), 30); + } + + return true; +}
diff --git a/sw/device/tests/sim_dv/BUILD b/sw/device/tests/sim_dv/BUILD index 8740d12..66a73fd 100644 --- a/sw/device/tests/sim_dv/BUILD +++ b/sw/device/tests/sim_dv/BUILD
@@ -8,32 +8,22 @@ matcha_dv_test( name = "uart_tx_rx_test", srcs = ["uart_tx_rx_test.c"], - targets = ["dv"], deps = [ - "//hw/top_matcha/ip/clkmgr/data/autogen:clkmgr_regs", - "//hw/top_matcha/ip/pinmux/data/autogen:pinmux_regs", - "//hw/top_matcha/sw/autogen:top_matcha", "//sw/device/lib/dif:clkmgr", + "//sw/device/lib/dif:pinmux", "//sw/device/lib/dif:rv_plic_sec", "//sw/device/lib/testing:clkmgr_testutils", - "//sw/device/lib/testing/test_framework:ottf_main", + "//sw/device/tests:test_dv_lib", "@lowrisc_opentitan//hw/ip/lc_ctrl/data:lc_ctrl_regs", - "@lowrisc_opentitan//sw/device/lib/base:mmio", "@lowrisc_opentitan//sw/device/lib/dif:lc_ctrl", "@lowrisc_opentitan//sw/device/lib/dif:uart", - "@lowrisc_opentitan//sw/device/lib/runtime:hart", - "@lowrisc_opentitan//sw/device/lib/runtime:irq", - "@lowrisc_opentitan//sw/device/lib/runtime:log", ], ) matcha_dv_test( name = "rv_dm_ndm_reset_req", srcs = ["rv_dm_ndm_reset_req.c"], - targets = ["dv"], deps = [ - "//hw/top_matcha/ip/pinmux/data/autogen:pinmux_regs", - "//hw/top_matcha/sw/autogen:top_matcha", "//sw/device/lib/dif:pinmux", "//sw/device/lib/dif:rstmgr", "//sw/device/tests:test_dv_lib", @@ -54,26 +44,103 @@ matcha_dv_test( name = "i2c_host_tx_rx_test", srcs = ["i2c_host_tx_rx_test.c"], - targets = ["dv"], deps = [ - "//hw/top_matcha/ip/pinmux/data/autogen:pinmux_regs", "//sw/device/lib/dif:pinmux", "//sw/device/lib/dif:rstmgr", + "//sw/device/lib/testing:isr_testutils", "//sw/device/tests:test_dv_lib", "@lowrisc_opentitan//sw/device/lib/dif:i2c", "@lowrisc_opentitan//sw/device/lib/testing:i2c_testutils", - "//sw/device/lib/testing:isr_testutils", "@lowrisc_opentitan//sw/device/lib/testing:rand_testutils", ], ) +cc_library( + name = "pwrmgr_reset_test_lib", + deps = [ + "//sw/device/lib/dif:alert_handler", + "//sw/device/lib/dif:pinmux", + "//sw/device/lib/dif:rstmgr", + "//sw/device/lib/dif:rv_plic_sec", + "//sw/device/lib/testing:pinmux_testutils", + "//sw/device/tests:test_dv_lib", + "@lowrisc_opentitan//sw/device/lib/base:abs_mmio", + "@lowrisc_opentitan//sw/device/lib/dif:aon_timer", + "@lowrisc_opentitan//sw/device/lib/dif:flash_ctrl", + "@lowrisc_opentitan//sw/device/lib/dif:pwrmgr", + "@lowrisc_opentitan//sw/device/lib/dif:rv_timer", + "@lowrisc_opentitan//sw/device/lib/dif:sysrst_ctrl", + "@lowrisc_opentitan//sw/device/lib/testing:alert_handler_testutils", + "@lowrisc_opentitan//sw/device/lib/testing:aon_timer_testutils", + "@lowrisc_opentitan//sw/device/lib/testing:flash_ctrl_testutils", + "@lowrisc_opentitan//sw/device/lib/testing:pwrmgr_testutils", + "@lowrisc_opentitan//sw/device/lib/testing:rstmgr_testutils", + "@lowrisc_opentitan//sw/device/lib/testing:rv_plic_testutils", + ], +) + +matcha_dv_test( + name = "pwrmgr_random_sleep_all_reset_reqs_test", + srcs = ["pwrmgr_random_sleep_all_reset_reqs_test.c"], + deps = [ + ":pwrmgr_reset_test_lib", + ], +) + +matcha_dv_test( + name = "pwrmgr_deep_sleep_all_reset_reqs_test", + srcs = ["pwrmgr_deep_sleep_all_reset_reqs_test.c"], + deps = [ + ":pwrmgr_reset_test_lib", + ], +) + +matcha_dv_test( + name = "pwrmgr_normal_sleep_all_reset_reqs_test", + srcs = ["pwrmgr_normal_sleep_all_reset_reqs_test.c"], + deps = [ + ":pwrmgr_reset_test_lib", + ], +) + +matcha_dv_test( + name = "pwrmgr_random_sleep_power_glitch_reset_test", + srcs = ["pwrmgr_random_sleep_power_glitch_reset_test.c"], + deps = [ + ":pwrmgr_reset_test_lib", + ], +) + +matcha_dv_test( + name = "pwrmgr_b2b_sleep_reset_test", + srcs = ["pwrmgr_b2b_sleep_reset_test.c"], + deps = [ + ":pwrmgr_reset_test_lib", + ], +) + +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", + ], +) + ################################################################################ # Place the Opentitan-sourced DV test below. # # Opentitan DV binary build flow does not support centOS7, so we pull the # # source code and build them here using `matcha_dv_test` rule. # ################################################################################ - matcha_dv_test( name = "spi_tx_rx_test", srcs = ["@lowrisc_opentitan//sw/device/tests/sim_dv:spi_tx_rx_test.c"], @@ -168,3 +235,39 @@ "@lowrisc_opentitan//sw/device/lib/testing:rv_plic_testutils", ], ) + +matcha_dv_test( + name = "pwrmgr_sleep_power_glitch_test", + srcs = ["@lowrisc_opentitan//sw/device/tests/sim_dv:pwrmgr_sleep_power_glitch_test.c"], + deps = [ + "//sw/device/lib/dif:rstmgr", + "//sw/device/tests:test_dv_lib_opentitan", + "@lowrisc_opentitan//sw/device/lib/dif:pwrmgr", + "@lowrisc_opentitan//sw/device/lib/testing:pwrmgr_testutils", + "@lowrisc_opentitan//sw/device/lib/testing:rstmgr_testutils", + ], +) + +matcha_dv_test( + name = "pwrmgr_deep_sleep_power_glitch_test", + srcs = ["@lowrisc_opentitan//sw/device/tests/sim_dv:pwrmgr_deep_sleep_power_glitch_test.c"], + deps = [ + "//sw/device/lib/dif:rstmgr", + "//sw/device/tests:test_dv_lib_opentitan", + "@lowrisc_opentitan//sw/device/lib/dif:pwrmgr", + "@lowrisc_opentitan//sw/device/lib/testing:pwrmgr_testutils", + "@lowrisc_opentitan//sw/device/lib/testing:rstmgr_testutils", + ], +) + +matcha_dv_test( + name = "gpio_test", + srcs = ["@lowrisc_opentitan//sw/device/tests/sim_dv:gpio_test.c"], + deps = [ + "//sw/device/lib/dif:rv_plic_sec", + "//sw/device/lib/testing:pinmux_testutils", + "//sw/device/tests:test_dv_lib_opentitan", + "@lowrisc_opentitan//sw/device/lib/dif:gpio", + "@lowrisc_opentitan//sw/device/lib/testing:rv_plic_testutils", + ], +)
diff --git a/sw/device/tests/sim_dv/pwrmgr_b2b_sleep_reset_test.c b/sw/device/tests/sim_dv/pwrmgr_b2b_sleep_reset_test.c new file mode 100644 index 0000000..35b3be0 --- /dev/null +++ b/sw/device/tests/sim_dv/pwrmgr_b2b_sleep_reset_test.c
@@ -0,0 +1,182 @@ +// 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 "aon_timer_regs.h" +#include "hw/top_matcha/sw/autogen/top_matcha.h" +#include "sw/device/lib/base/abs_mmio.h" +#include "sw/device/lib/base/mmio.h" +#include "sw/device/lib/dif/dif_aon_timer.h" +#include "sw/device/lib/dif/dif_flash_ctrl.h" +#include "sw/device/lib/dif/dif_pinmux.h" +#include "sw/device/lib/dif/dif_pwrmgr.h" +#include "sw/device/lib/dif/dif_rstmgr.h" +#include "sw/device/lib/dif/dif_sysrst_ctrl.h" +#include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/aon_timer_testutils.h" +#include "sw/device/lib/testing/flash_ctrl_testutils.h" +#include "sw/device/lib/testing/pwrmgr_testutils.h" +#include "sw/device/lib/testing/rstmgr_testutils.h" +#include "sw/device/lib/testing/test_framework/check.h" +#include "sw/device/lib/testing/test_framework/ottf_main.h" +/* + PWRMGR BACK TO BACK DEEP SLEEP, RESET / WAKEUP TEST + + This test introduces reset or wakeup event close to (before or after) + entering low power state. + + 'kNumRound' is set to 10 by sv sequence (chip_sw_repeat_reset_wkup_vseq.sv) + + For the reset event, the sequence assert power on resest by driving POR_N + PAD. For the wake up event, the seqeunce assert power button in by driving + IOR13 PAD. + + */ +OTTF_DEFINE_TEST_CONFIG(); + +static volatile const uint8_t kNumRound; + +static dif_flash_ctrl_state_t flash_ctrl; +static dif_sysrst_ctrl_t sysrst_ctrl; +static dif_pinmux_t pinmux; + +/** + * sysrst_ctrl config for test #1 + * . set sysrst_ctrl.KEY_INTR_CTL.pwrb_in_H2L to 1 + * . use IOR13 as pwrb_in + */ +static void prgm_push_button_wakeup() { + dif_sysrst_ctrl_input_change_config_t config = { + .input_changes = kDifSysrstCtrlInputPowerButtonH2L, + .debounce_time_threshold = 1, // 5us + }; + CHECK_DIF_OK( + dif_sysrst_ctrl_input_change_detect_configure(&sysrst_ctrl, config)); + CHECK_DIF_OK(dif_pinmux_input_select( + &pinmux, kTopMatchaPinmuxPeripheralInSysrstCtrlAonPwrbIn, + kTopMatchaPinmuxInselIor13)); +} + +bool test_main(void) { + // Issue a wakeup signal in ~1.5 ms through the AON timer. + // This timer is needed when reset or wakeup fail to + // bring state machine back to active state. + // This can happen when wake up event comes before low power + // entry event. + uint32_t wakeup_threshold = kDeviceType == kDeviceSimVerilator ? 3000 : 300; + + // Initialize pwrmgr + dif_pwrmgr_t pwrmgr; + CHECK_DIF_OK(dif_pwrmgr_init( + mmio_region_from_addr(TOP_MATCHA_PWRMGR_AON_BASE_ADDR), &pwrmgr)); + + // Initialize rstmgr since this will check some registers. + dif_rstmgr_t rstmgr; + CHECK_DIF_OK(dif_rstmgr_init( + mmio_region_from_addr(TOP_MATCHA_RSTMGR_AON_BASE_ADDR), &rstmgr)); + + // Initialize flash_ctrl + CHECK_DIF_OK(dif_flash_ctrl_init_state( + &flash_ctrl, + mmio_region_from_addr(TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR))); + + // Initialize sysrst_ctrl + CHECK_DIF_OK(dif_sysrst_ctrl_init( + mmio_region_from_addr(TOP_MATCHA_SYSRST_CTRL_AON_BASE_ADDR), + &sysrst_ctrl)); + + // Initialize pinmux + CHECK_DIF_OK(dif_pinmux_init( + mmio_region_from_addr(TOP_MATCHA_PINMUX_AON_BASE_ADDR), &pinmux)); + + // First check the flash stored value + uint32_t event_idx = flash_ctrl_testutils_counter_get(0); + // Enable flash access + flash_ctrl_testutils_default_region_access(&flash_ctrl, + /*rd_en*/ true, + /*prog_en*/ true, + /*erase_en*/ true, + /*scramble_en*/ false, + /*ecc_en*/ false, + /*he_en*/ false); + + // Increment flash counter to know where we are + flash_ctrl_testutils_counter_increment(&flash_ctrl, 0); + + // Read wakeup reason before check + dif_pwrmgr_wakeup_reason_t wakeup_reason; + CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason)); + LOG_INFO("wakeup type:%d wakeup reason: 0x%02X", wakeup_reason.types, + wakeup_reason.request_sources); + + if (wakeup_reason.types == 0) { + // POR reset + CHECK(wakeup_reason.request_sources == 0); + } else if (wakeup_reason.types == kDifPwrmgrWakeupTypeRequest) { + // sysrst_ctrl or aon_timer + CHECK(wakeup_reason.request_sources == (kDifPwrmgrWakeupRequestSourceOne | + kDifPwrmgrWakeupRequestSourceFive)); + } else { + LOG_ERROR("unexpected wakeup_type: 0x%x", wakeup_reason.types); + } + + // Read reset info before check + dif_rstmgr_reset_info_bitfield_t rst_info; + rst_info = rstmgr_testutils_reason_get(); + rstmgr_testutils_reason_clear(); + LOG_INFO("reset info = 0x%02X", rst_info); + + if (rst_info != kDifRstmgrResetInfoPor && + rst_info != kDifRstmgrResetInfoLowPowerExit) { + LOG_ERROR("unexpected reset info: 0x%x", rst_info); + } + + dif_aon_timer_t aon_timer; + CHECK_DIF_OK(dif_aon_timer_init( + mmio_region_from_addr(TOP_MATCHA_AON_TIMER_AON_BASE_ADDR), &aon_timer)); + + // Status clean up + if (event_idx > 0) { + // aon timer clean up + CHECK_DIF_OK(dif_aon_timer_wakeup_stop(&aon_timer)); + // mmio_region_write32( + // mmio_region_from_addr(TOP_MATCHA_AON_TIMER_AON_BASE_ADDR), + // AON_TIMER_WKUP_CAUSE_REG_OFFSET, 0); + CHECK_DIF_OK(dif_aon_timer_clear_wakeup_cause(&aon_timer)); + // sysrst ctrl status clean up + CHECK_DIF_OK(dif_sysrst_ctrl_ulp_wakeup_clear_status(&sysrst_ctrl)); + } + + if (event_idx < kNumRound) { + LOG_INFO("Test round %d", event_idx); + } else { + LOG_INFO("Test finish"); + return true; + } + + // pin mux / sysrst ctrl set up for push button wakeup + prgm_push_button_wakeup(); + + // Prepare rstmgr for a reset. + rstmgr_testutils_pre_reset(&rstmgr); + + // This is mark for sv sequence to prepare to asserting parallel event. + LOG_INFO("ready for power down"); + busy_spin_micros(10); + // timer setup in case wake up comes before entering low power mode + aon_timer_testutils_wakeup_config(&aon_timer, wakeup_threshold); + + // Deep sleep. + pwrmgr_testutils_enable_low_power( + &pwrmgr, + (kDifPwrmgrWakeupRequestSourceOne | kDifPwrmgrWakeupRequestSourceTwo | + kDifPwrmgrWakeupRequestSourceThree | kDifPwrmgrWakeupRequestSourceFour | + kDifPwrmgrWakeupRequestSourceFive | kDifPwrmgrWakeupRequestSourceSix), + 0); + + // Enter low power mode. + wait_for_interrupt(); + + return false; +}
diff --git a/sw/device/tests/sim_dv/pwrmgr_deep_sleep_all_reset_reqs_test.c b/sw/device/tests/sim_dv/pwrmgr_deep_sleep_all_reset_reqs_test.c new file mode 100644 index 0000000..b5f3191 --- /dev/null +++ b/sw/device/tests/sim_dv/pwrmgr_deep_sleep_all_reset_reqs_test.c
@@ -0,0 +1,520 @@ +// 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 <assert.h> +#include <limits.h> +#include <stdbool.h> +#include <stdint.h> + +#include "hw/top_matcha/sw/autogen/top_matcha.h" +#include "sw/device/lib/base/abs_mmio.h" +#include "sw/device/lib/base/math.h" +#include "sw/device/lib/base/mmio.h" +#include "sw/device/lib/dif/dif_alert_handler.h" +#include "sw/device/lib/dif/dif_aon_timer.h" +#include "sw/device/lib/dif/dif_flash_ctrl.h" +#include "sw/device/lib/dif/dif_pinmux.h" +#include "sw/device/lib/dif/dif_pwrmgr.h" +#include "sw/device/lib/dif/dif_rstmgr.h" +#include "sw/device/lib/dif/dif_rv_plic.h" +#include "sw/device/lib/dif/dif_rv_timer.h" +#include "sw/device/lib/dif/dif_sysrst_ctrl.h" +#include "sw/device/lib/runtime/irq.h" +#include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/alert_handler_testutils.h" +#include "sw/device/lib/testing/aon_timer_testutils.h" +#include "sw/device/lib/testing/flash_ctrl_testutils.h" +#include "sw/device/lib/testing/pwrmgr_testutils.h" +#include "sw/device/lib/testing/rstmgr_testutils.h" +#include "sw/device/lib/testing/rv_plic_testutils.h" +#include "sw/device/lib/testing/test_framework/FreeRTOSConfig.h" +#include "sw/device/lib/testing/test_framework/check.h" +#include "sw/device/lib/testing/test_framework/ottf_main.h" + +// In dvsim, one run +// with --waves can take +// 1.874h | 38.068ms +// without --waves, +// 38.072m | 39.484ms + +OTTF_DEFINE_TEST_CONFIG(); +static volatile const uint8_t RST_IDX[7] = {0, 1, 2, 3, 4, 5, 6}; +static const uint32_t kPlicTarget = kTopMatchaPlicTargetIbex0; + +/** + * Objects to access the peripherals used in this test via dif API. + */ +static dif_flash_ctrl_state_t flash_ctrl; +static dif_rv_plic_t plic; +static dif_alert_handler_t alert_handler; +static dif_aon_timer_t aon_timer; +static dif_pwrmgr_t pwrmgr; +static dif_sysrst_ctrl_t sysrst_ctrl_aon; +static dif_rstmgr_t rstmgr; + +/** + * Program the alert handler to escalate on alerts upto phase 2 (i.e. reset) but + * the phase 1 (i.e. wipe secrets) should occur and last during the time the + * wdog is programed to bark. + * + * Notice these settings are suitable for sim_dv. For other platforms we scale + * the resulting cycles by a factor of 10. + */ +enum { + kWdogBarkMicros = 3 * 100, // 300 us + kWdogBiteMicros = 4 * 100, // 400 us + kEscalationPhase0Micros = 1 * 100, // 100 us + // The cpu value is slightly larger to avoid flakey results. + kEscalationPhase0MicrosCpu = kEscalationPhase0Micros + 20, // 120 us + kEscalationPhase1Micros = 5 * 100, // 500 us + kEscalationPhase2Micros = 50, // 50 us +}; + +static_assert( + kWdogBarkMicros < kWdogBiteMicros && + kWdogBarkMicros > kEscalationPhase0Micros && + kWdogBarkMicros < (kEscalationPhase0Micros + kEscalationPhase1Micros) && + kWdogBiteMicros < (kEscalationPhase0Micros + kEscalationPhase1Micros), + "The wdog bark and bite shall happens during the escalation phase 1"); + +/** + * External ISR. + * + * Handles all peripheral interrupts on Ibex. PLIC asserts an external interrupt + * line to the CPU, which results in a call to this OTTF ISR. This ISR + * overrides the default OTTF implementation. + */ +void ottf_external_isr(void) { + top_matcha_plic_peripheral_t peripheral; + dif_rv_plic_irq_id_t irq_id; + uint32_t irq = 0; + uint32_t alert = 0; + + CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic, kPlicTarget, &irq_id)); + + peripheral = (top_matcha_plic_peripheral_t) + top_matcha_plic_interrupt_for_peripheral[irq_id]; + + if (peripheral == kTopMatchaPlicPeripheralAonTimerAon) { + irq = + (dif_aon_timer_irq_t)(irq_id - + (dif_rv_plic_irq_id_t) + kTopMatchaPlicIrqIdAonTimerAonWkupTimerExpired); + + // Stops escalation process. + CHECK_DIF_OK(dif_alert_handler_escalation_clear(&alert_handler, + kDifAlertHandlerClassA)); + CHECK_DIF_OK(dif_aon_timer_irq_acknowledge(&aon_timer, irq)); + + CHECK(irq != kTopMatchaPlicIrqIdAonTimerAonWdogTimerBark, + "AON Timer Wdog should not bark"); + + } else if (peripheral == kTopMatchaPlicPeripheralAlertHandler) { + irq = (dif_rv_plic_irq_id_t)(irq_id - + (dif_rv_plic_irq_id_t) + kTopMatchaPlicIrqIdAlertHandlerClassa); + + CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(&alert_handler, alert)); + + dif_alert_handler_class_state_t state; + CHECK_DIF_OK(dif_alert_handler_get_class_state( + &alert_handler, kDifAlertHandlerClassA, &state)); + + CHECK(state == kDifAlertHandlerClassStatePhase0, "Wrong phase %d", state); + + CHECK_DIF_OK(dif_alert_handler_irq_acknowledge(&alert_handler, irq)); + } + + // Complete the IRQ by writing the IRQ source to the Ibex specific CC + // register. + CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic, kPlicTarget, irq_id)); +} + +/** + * Initialize the peripherals used in this test. + */ +void init_peripherals(void) { + // Initialize pwrmgr. + CHECK_DIF_OK(dif_pwrmgr_init( + mmio_region_from_addr(TOP_MATCHA_PWRMGR_AON_BASE_ADDR), &pwrmgr)); + + // Initialize sysrst_ctrl. + CHECK_DIF_OK(dif_sysrst_ctrl_init( + mmio_region_from_addr(TOP_MATCHA_SYSRST_CTRL_AON_BASE_ADDR), + &sysrst_ctrl_aon)); + + // Initialize rstmgr to check the reset reason. + CHECK_DIF_OK(dif_rstmgr_init( + mmio_region_from_addr(TOP_MATCHA_RSTMGR_AON_BASE_ADDR), &rstmgr)); + + // Initialize aon timer to use the wdog. + CHECK_DIF_OK(dif_aon_timer_init( + mmio_region_from_addr(TOP_MATCHA_AON_TIMER_AON_BASE_ADDR), &aon_timer)); + + // Initialize flash_ctrl + CHECK_DIF_OK(dif_flash_ctrl_init_state( + &flash_ctrl, + mmio_region_from_addr(TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR))); + + // Initialize plic. + CHECK_DIF_OK(dif_rv_plic_init( + mmio_region_from_addr(TOP_MATCHA_RV_PLIC_BASE_ADDR), &plic)); + + rv_plic_testutils_irq_range_enable( + &plic, kPlicTarget, kTopMatchaPlicIrqIdAonTimerAonWkupTimerExpired, + kTopMatchaPlicIrqIdAonTimerAonWdogTimerBark); + + // Initialize alert handler. + CHECK_DIF_OK(dif_alert_handler_init( + mmio_region_from_addr(TOP_MATCHA_ALERT_HANDLER_BASE_ADDR), + &alert_handler)); +} + +/** + * Program the alert handler to escalate on alerts upto phase 2 (i.e. reset) but + * the phase 1 (i.e. wipe secrets) should occur and last during the time the + * wdog is programed to bark. + */ +static void alert_handler_config(void) { + dif_alert_handler_alert_t alerts[] = {kTopMatchaAlertIdPwrmgrAonFatalFault}; + dif_alert_handler_class_t alert_classes[] = {kDifAlertHandlerClassA}; + + dif_alert_handler_escalation_phase_t esc_phases[] = { + {.phase = kDifAlertHandlerClassStatePhase0, + .signal = 0, + .duration_cycles = + alert_handler_testutils_get_cycles_from_us(kEscalationPhase0Micros) * + alert_handler_testutils_cycle_rescaling_factor()}, + {.phase = kDifAlertHandlerClassStatePhase1, + .signal = 1, + .duration_cycles = + alert_handler_testutils_get_cycles_from_us(kEscalationPhase1Micros) * + alert_handler_testutils_cycle_rescaling_factor()}, + {.phase = kDifAlertHandlerClassStatePhase2, + .signal = 3, + .duration_cycles = + alert_handler_testutils_get_cycles_from_us(kEscalationPhase2Micros) * + alert_handler_testutils_cycle_rescaling_factor()}}; + + dif_alert_handler_class_config_t class_config[] = {{ + .auto_lock_accumulation_counter = kDifToggleDisabled, + .accumulator_threshold = 0, + .irq_deadline_cycles = alert_handler_testutils_get_cycles_from_us(10) * + alert_handler_testutils_cycle_rescaling_factor(), + .escalation_phases = esc_phases, + .escalation_phases_len = ARRAYSIZE(esc_phases), + .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase3, + }}; + + dif_alert_handler_class_t classes[] = {kDifAlertHandlerClassA}; + dif_alert_handler_config_t config = { + .alerts = alerts, + .alert_classes = alert_classes, + .alerts_len = ARRAYSIZE(alerts), + .classes = classes, + .class_configs = class_config, + .classes_len = ARRAYSIZE(class_config), + .ping_timeout = 0, + }; + + alert_handler_testutils_configure_all(&alert_handler, config, + kDifToggleEnabled); + // Enables alert handler irq. + CHECK_DIF_OK(dif_alert_handler_irq_set_enabled( + &alert_handler, kDifAlertHandlerIrqClassa, kDifToggleEnabled)); +} + +/** + * Execute the aon timer interrupt test. + */ +static void trigger_escalate(dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr) { + uint64_t bark_cycles = + udiv64_slow(kWdogBarkMicros * kClockFreqAonHz, 1000000, NULL) * + alert_handler_testutils_cycle_rescaling_factor(); + uint64_t bite_cycles = + udiv64_slow(kWdogBiteMicros * kClockFreqAonHz, 1000000, NULL) * + alert_handler_testutils_cycle_rescaling_factor(); + + CHECK(bite_cycles < UINT32_MAX, + "The value %u can't fit into the 32 bits timer counter.", bite_cycles); + + LOG_INFO( + "Wdog will bark after %u/%u us/cycles and bite after %u/%u us/cycles", + (uint32_t)kWdogBarkMicros, (uint32_t)bark_cycles, + (uint32_t)kWdogBiteMicros, (uint32_t)bite_cycles); + + // Setup the wdog bark and bite timeouts. + aon_timer_testutils_watchdog_config(aon_timer, bark_cycles, bite_cycles, + false); + + // Trigger the alert handler to escalate. + dif_pwrmgr_alert_t alert = kDifPwrmgrAlertFatalFault; + CHECK_DIF_OK(dif_pwrmgr_alert_force(pwrmgr, alert)); +} + +/** + * Configure the sysrst. + */ +static void config_sysrst(const dif_pwrmgr_t *pwrmgr, + const dif_sysrst_ctrl_t *sysrst_ctrl_aon) { + LOG_INFO("sysrst enabled"); + + // Set sysrst as a reset source. + CHECK_DIF_OK(dif_pwrmgr_set_request_sources(pwrmgr, kDifPwrmgrReqTypeReset, + kDifPwrmgrResetRequestSourceOne, + kDifToggleEnabled)); + LOG_INFO("Reset Request SourceOne is set"); + + // Configure sysrst key combo + // reset pulse : 50 us + // detect durration : 50 us + + dif_sysrst_ctrl_key_combo_config_t sysrst_ctrl_key_combo_config = { + .keys = kDifSysrstCtrlKeyAll, + .detection_time_threshold = 10, + .actions = kDifSysrstCtrlKeyComboActionAll, + .embedded_controller_reset_duration = 10}; + + CHECK_DIF_OK(dif_sysrst_ctrl_key_combo_detect_configure( + sysrst_ctrl_aon, kDifSysrstCtrlKeyCombo0, sysrst_ctrl_key_combo_config)); + // Configure sysrst input change + // debounce durration : 100 us + dif_sysrst_ctrl_input_change_config_t sysrst_ctrl_input_change_config = { + .input_changes = kDifSysrstCtrlInputAll, .debounce_time_threshold = 20}; + + // Configure pinmux + dif_pinmux_t pinmux; + CHECK_DIF_OK(dif_pinmux_init( + mmio_region_from_addr(TOP_MATCHA_PINMUX_AON_BASE_ADDR), &pinmux)); + + CHECK_DIF_OK(dif_sysrst_ctrl_input_change_detect_configure( + sysrst_ctrl_aon, sysrst_ctrl_input_change_config)); + + CHECK_DIF_OK(dif_pinmux_input_select( + &pinmux, kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey0In, + kTopMatchaPinmuxInselIor13)); +} + +static void low_power_sysrst(const dif_pwrmgr_t *pwrmgr) { + // Program the pwrmgr to go to deep sleep state (clocks off). + pwrmgr_testutils_enable_low_power(pwrmgr, kDifPwrmgrWakeupRequestSourceOne, + 0); + LOG_INFO("Low power set for sysrst"); + + // Enter in low power mode. + wait_for_interrupt(); +} + +static void timer_on(uint32_t usec) { + busy_spin_micros(usec); + // If we arrive here the test must fail. + CHECK(false, "Timeout waiting for reset!"); +} + +/** + * Configure the wdog. + */ +static void config_wdog(const dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr, uint64_t bark_time_us, + uint64_t bite_time_us) { + uint32_t bark_cycles = + aon_timer_testutils_get_aon_cycles_from_us(bark_time_us); + uint32_t bite_cycles = + aon_timer_testutils_get_aon_cycles_from_us(bite_time_us); + + LOG_INFO("Wdog will bark after %u us and bite after %u us", + (uint32_t)bark_time_us, (uint32_t)bite_time_us); + // Setup the wdog bark and bite timeouts. + aon_timer_testutils_watchdog_config(aon_timer, bark_cycles, bite_cycles, + false); + // Set wdog as a reset source. + CHECK_DIF_OK(dif_pwrmgr_set_request_sources(pwrmgr, kDifPwrmgrReqTypeReset, + kDifPwrmgrResetRequestSourceTwo, + kDifToggleEnabled)); +} + +/** + * Execute the aon timer wdog bite reset test. + */ +static void wdog_bite_test(const dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr, uint64_t bark_time_us) { + uint64_t bite_time_us = bark_time_us * 2; + config_wdog(aon_timer, pwrmgr, bark_time_us, bite_time_us); + + // The `intr_state` takes 3 aon clock cycles to rise plus 2 extra cycles as a + // precaution. + uint32_t wait_us = + bark_time_us + + udiv64_slow(5 * 1000000 + kClockFreqAonHz - 1, kClockFreqAonHz, NULL); + + // Wait bark time and check that the bark interrupt requested. + busy_spin_micros(wait_us); + bool is_pending = false; + CHECK_DIF_OK(dif_aon_timer_irq_is_pending( + aon_timer, kDifAonTimerIrqWdogTimerBark, &is_pending)); + CHECK(is_pending, "Wdog bark irq did not rise after %u microseconds", + wait_us); + + // Wait for the remaining time to the wdog bite. + busy_spin_micros(wait_us); + // If we arrive here the test must fail. + CHECK(false, "Timeout waiting for Wdog bite reset!"); +} + +/** + * Execute the aon timer wdog bite reset during sleep test. + */ +static void sleep_wdog_bite_test(const dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr, + uint64_t bark_time_us) { + uint64_t bite_time_us = bark_time_us * 2; + config_wdog(aon_timer, pwrmgr, bark_time_us, bite_time_us); +} + +static void low_power_wdog(const dif_pwrmgr_t *pwrmgr) { + // Program the pwrmgr to go to deep sleep state (clocks off). + pwrmgr_testutils_enable_low_power(pwrmgr, kDifPwrmgrWakeupRequestSourceTwo, + 0); + LOG_INFO("Low power set for watch dog"); + wait_for_interrupt(); + // If we arrive here the test must fail. + CHECK(false, "Fail to enter in low power mode!"); +} + +static void low_power_por(const dif_pwrmgr_t *pwrmgr) { + // Set por as a reset source. + CHECK_DIF_OK(dif_pwrmgr_set_request_sources(pwrmgr, kDifPwrmgrReqTypeReset, + kDifPwrmgrResetRequestSourceTwo, + kDifToggleEnabled)); + + // Program the pwrmgr to go to deep sleep state (clocks off). + pwrmgr_testutils_enable_low_power( + pwrmgr, + (kDifPwrmgrWakeupRequestSourceOne | kDifPwrmgrWakeupRequestSourceTwo | + kDifPwrmgrWakeupRequestSourceThree | kDifPwrmgrWakeupRequestSourceFour | + kDifPwrmgrWakeupRequestSourceFive | kDifPwrmgrWakeupRequestSourceSix), + 0); + LOG_INFO("ready for pad por"); + + // Enter in low power mode. + wait_for_interrupt(); + // If we arrive here the test must fail. + CHECK(false, "Fail to enter in low power mode!"); +} + +bool test_main(void) { + // Enable global and external IRQ at Ibex. + irq_global_ctrl(true); + irq_external_ctrl(true); + + init_peripherals(); + + // Enable all the AON interrupts used in this test. + rv_plic_testutils_irq_range_enable(&plic, kPlicTarget, + kTopMatchaPlicIrqIdAlertHandlerClassa, + kTopMatchaPlicIrqIdAlertHandlerClassd); + + alert_handler_config(); + + // First check the flash stored value. + uint32_t event_idx = flash_ctrl_testutils_counter_get(0); + + // Enable flash access + flash_ctrl_testutils_default_region_access(&flash_ctrl, + /*rd_en*/ true, + /*prog_en*/ true, + /*erase_en*/ true, + /*scramble_en*/ false, + /*ecc_en*/ false, + /*he_en*/ false); + + // Increment flash counter to know where we are. + flash_ctrl_testutils_counter_increment(&flash_ctrl, 0); + + LOG_INFO("Test round %d", event_idx); + LOG_INFO("RST_IDX[%d] = %d", event_idx, RST_IDX[event_idx]); + + // Check if there was a HW reset caused by expected cases. + dif_rstmgr_reset_info_bitfield_t rst_info; + rst_info = rstmgr_testutils_reason_get(); + rstmgr_testutils_reason_clear(); + + CHECK(rst_info == kDifRstmgrResetInfoPor || + rst_info == kDifRstmgrResetInfoSysRstCtrl || + rst_info == kDifRstmgrResetInfoWatchdog || + rst_info == kDifRstmgrResetInfoEscalation || + rst_info == kDifRstmgrResetInfoLowPowerExit || + rst_info == (kDifRstmgrResetInfoSysRstCtrl | + kDifRstmgrResetInfoLowPowerExit) || + rst_info == + (kDifRstmgrResetInfoPor | kDifRstmgrResetInfoLowPowerExit) || + rst_info == (kDifRstmgrResetInfoWatchdog | + kDifRstmgrResetInfoLowPowerExit) || + rst_info == (kDifRstmgrResetInfoEscalation | + kDifRstmgrResetInfoLowPowerExit) || + rst_info == kDifRstmgrResetInfoSw, + "Wrong reset reason %02X", rst_info); + + switch (RST_IDX[event_idx]) { + case 0: + LOG_INFO("Booting and setting deep sleep followed by sysrst"); + config_sysrst(&pwrmgr, &sysrst_ctrl_aon); + low_power_sysrst(&pwrmgr); + break; + case 1: + LOG_INFO("Booting and setting deep sleep followed by hw por"); + low_power_por(&pwrmgr); + break; + case 2: + LOG_INFO( + "Booting and setting deep sleep mode followed for low_power entry " + "reset"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + // actually the same test as deep sleep + watchdog + rstmgr_testutils_pre_reset(&rstmgr); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + low_power_wdog(&pwrmgr); + break; + case 3: + LOG_INFO( + "Booting and setting deep sleep followed by watchdog reset " + "combined " + "with sw_req"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + rstmgr_testutils_pre_reset(&rstmgr); + + // Assert reeset req + CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr)); + LOG_INFO("Device reset from sw"); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + low_power_wdog(&pwrmgr); + break; + case 4: + LOG_INFO("Booting and setting deep sleep followed by watchdog reset"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + rstmgr_testutils_pre_reset(&rstmgr); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + low_power_wdog(&pwrmgr); + break; + case 5: + LOG_INFO("Booting and running normal sleep followed by escalation reset"); + LOG_INFO("Let SV wait timer reset"); + trigger_escalate(&aon_timer, &pwrmgr); + timer_on(kEscalationPhase0MicrosCpu); + break; + case 6: + LOG_INFO("Last Booting"); + return true; + break; + default: + LOG_INFO("Booting for undefined case"); + } + + return false; +}
diff --git a/sw/device/tests/sim_dv/pwrmgr_normal_sleep_all_reset_reqs_test.c b/sw/device/tests/sim_dv/pwrmgr_normal_sleep_all_reset_reqs_test.c new file mode 100644 index 0000000..151b9c5 --- /dev/null +++ b/sw/device/tests/sim_dv/pwrmgr_normal_sleep_all_reset_reqs_test.c
@@ -0,0 +1,532 @@ +// 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 <assert.h> +#include <limits.h> +#include <stdbool.h> +#include <stdint.h> + +#include "hw/top_matcha/sw/autogen/top_matcha.h" +#include "sw/device/lib/base/abs_mmio.h" +#include "sw/device/lib/base/math.h" +#include "sw/device/lib/base/mmio.h" +#include "sw/device/lib/dif/dif_alert_handler.h" +#include "sw/device/lib/dif/dif_aon_timer.h" +#include "sw/device/lib/dif/dif_flash_ctrl.h" +#include "sw/device/lib/dif/dif_pinmux.h" +#include "sw/device/lib/dif/dif_pwrmgr.h" +#include "sw/device/lib/dif/dif_rstmgr.h" +#include "sw/device/lib/dif/dif_rv_plic.h" +#include "sw/device/lib/dif/dif_rv_timer.h" +#include "sw/device/lib/dif/dif_sysrst_ctrl.h" +#include "sw/device/lib/runtime/irq.h" +#include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/alert_handler_testutils.h" +#include "sw/device/lib/testing/aon_timer_testutils.h" +#include "sw/device/lib/testing/flash_ctrl_testutils.h" +#include "sw/device/lib/testing/pwrmgr_testutils.h" +#include "sw/device/lib/testing/rstmgr_testutils.h" +#include "sw/device/lib/testing/rv_plic_testutils.h" +#include "sw/device/lib/testing/test_framework/FreeRTOSConfig.h" +#include "sw/device/lib/testing/test_framework/check.h" +#include "sw/device/lib/testing/test_framework/ottf_main.h" + +OTTF_DEFINE_TEST_CONFIG(); +static volatile const uint8_t RST_IDX[7] = {0, 1, 2, 3, 4, 5, 6}; +static const uint32_t kPlicTarget = kTopMatchaPlicTargetIbex0; + +/** + * Objects to access the peripherals used in this test via dif API. + */ +static dif_flash_ctrl_state_t flash_ctrl; +static dif_rv_plic_t plic; +static dif_alert_handler_t alert_handler; +static dif_aon_timer_t aon_timer; +static dif_pwrmgr_t pwrmgr; +static dif_sysrst_ctrl_t sysrst_ctrl_aon; +static dif_rstmgr_t rstmgr; + +/** + * Program the alert handler to escalate on alerts upto phase 2 (i.e. reset) but + * the phase 1 (i.e. wipe secrets) should occur and last during the time the + * wdog is programed to bark. + * + * Notice these settings are suitable for sim_dv. For other platforms we scale + * the resulting cycles by a factor of 10. + */ +enum { + kWdogBarkMicros = 3 * 100, // 300 us + kWdogBiteMicros = 4 * 100, // 400 us + kEscalationPhase0Micros = 1 * 100, // 100 us + // The cpu value is slightly larger to avoid flakey results. + kEscalationPhase0MicrosCpu = kEscalationPhase0Micros + 20, // 120 us + kEscalationPhase1Micros = 5 * 100, // 500 us + kEscalationPhase2Micros = 50, // 50 us +}; + +static_assert( + kWdogBarkMicros < kWdogBiteMicros && + kWdogBarkMicros > kEscalationPhase0Micros && + kWdogBarkMicros < (kEscalationPhase0Micros + kEscalationPhase1Micros) && + kWdogBiteMicros < (kEscalationPhase0Micros + kEscalationPhase1Micros), + "The wdog bark and bite shall happens during the escalation phase 1"); + +/** + * External ISR. + * + * Handles all peripheral interrupts on Ibex. PLIC asserts an external interrupt + * line to the CPU, which results in a call to this OTTF ISR. This ISR + * overrides the default OTTF implementation. + */ +void ottf_external_isr(void) { + top_matcha_plic_peripheral_t peripheral; + dif_rv_plic_irq_id_t irq_id; + uint32_t irq = 0; + uint32_t alert = 0; + + CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic, kPlicTarget, &irq_id)); + + peripheral = (top_matcha_plic_peripheral_t) + top_matcha_plic_interrupt_for_peripheral[irq_id]; + + if (peripheral == kTopMatchaPlicPeripheralAonTimerAon) { + irq = + (dif_aon_timer_irq_t)(irq_id - + (dif_rv_plic_irq_id_t) + kTopMatchaPlicIrqIdAonTimerAonWkupTimerExpired); + + // Stops escalation process. + CHECK_DIF_OK(dif_alert_handler_escalation_clear(&alert_handler, + kDifAlertHandlerClassA)); + CHECK_DIF_OK(dif_aon_timer_irq_acknowledge(&aon_timer, irq)); + + CHECK(irq != kTopMatchaPlicIrqIdAonTimerAonWdogTimerBark, + "AON Timer Wdog should not bark"); + + } else if (peripheral == kTopMatchaPlicPeripheralAlertHandler) { + irq = (dif_aon_timer_irq_t)(irq_id - + (dif_rv_plic_irq_id_t) + kTopMatchaPlicIrqIdAlertHandlerClassa); + + CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(&alert_handler, alert)); + + dif_alert_handler_class_state_t state; + CHECK_DIF_OK(dif_alert_handler_get_class_state( + &alert_handler, kDifAlertHandlerClassA, &state)); + + CHECK(state == kDifAlertHandlerClassStatePhase0, "Wrong phase %d", state); + + CHECK_DIF_OK(dif_alert_handler_irq_acknowledge(&alert_handler, irq)); + } + + // Complete the IRQ by writing the IRQ source to the Ibex specific CC + // register. + CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic, kPlicTarget, irq_id)); +} + +/** + * Initialize the peripherals used in this test. + */ +void init_peripherals(void) { + // Initialize pwrmgr. + CHECK_DIF_OK(dif_pwrmgr_init( + mmio_region_from_addr(TOP_MATCHA_PWRMGR_AON_BASE_ADDR), &pwrmgr)); + + // Initialize sysrst_ctrl. + CHECK_DIF_OK(dif_sysrst_ctrl_init( + mmio_region_from_addr(TOP_MATCHA_SYSRST_CTRL_AON_BASE_ADDR), + &sysrst_ctrl_aon)); + + // Initialize rstmgr to check the reset reason. + CHECK_DIF_OK(dif_rstmgr_init( + mmio_region_from_addr(TOP_MATCHA_RSTMGR_AON_BASE_ADDR), &rstmgr)); + + // Initialize aon timer to use the wdog. + CHECK_DIF_OK(dif_aon_timer_init( + mmio_region_from_addr(TOP_MATCHA_AON_TIMER_AON_BASE_ADDR), &aon_timer)); + + // Initialize flash_ctrl + CHECK_DIF_OK(dif_flash_ctrl_init_state( + &flash_ctrl, + mmio_region_from_addr(TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR))); + + // Initialize plic. + CHECK_DIF_OK(dif_rv_plic_init( + mmio_region_from_addr(TOP_MATCHA_RV_PLIC_BASE_ADDR), &plic)); + + rv_plic_testutils_irq_range_enable( + &plic, kPlicTarget, kTopMatchaPlicIrqIdAonTimerAonWkupTimerExpired, + kTopMatchaPlicIrqIdAonTimerAonWdogTimerBark); + + // Initialize alert handler. + CHECK_DIF_OK(dif_alert_handler_init( + mmio_region_from_addr(TOP_MATCHA_ALERT_HANDLER_BASE_ADDR), + &alert_handler)); +} + +/** + * Program the alert handler to escalate on alerts upto phase 2 (i.e. reset) but + * the phase 1 (i.e. wipe secrets) should occur and last during the time the + * wdog is programed to bark. + */ +static void alert_handler_config(void) { + dif_alert_handler_alert_t alerts[] = {kTopMatchaAlertIdPwrmgrAonFatalFault}; + dif_alert_handler_class_t alert_classes[] = {kDifAlertHandlerClassA}; + + dif_alert_handler_escalation_phase_t esc_phases[] = { + {.phase = kDifAlertHandlerClassStatePhase0, + .signal = 0, + .duration_cycles = + alert_handler_testutils_get_cycles_from_us(kEscalationPhase0Micros) * + alert_handler_testutils_cycle_rescaling_factor()}, + {.phase = kDifAlertHandlerClassStatePhase1, + .signal = 1, + .duration_cycles = + alert_handler_testutils_get_cycles_from_us(kEscalationPhase1Micros) * + alert_handler_testutils_cycle_rescaling_factor()}, + {.phase = kDifAlertHandlerClassStatePhase2, + .signal = 3, + .duration_cycles = + alert_handler_testutils_get_cycles_from_us(kEscalationPhase2Micros) * + alert_handler_testutils_cycle_rescaling_factor()}}; + + dif_alert_handler_class_config_t class_config[] = {{ + .auto_lock_accumulation_counter = kDifToggleDisabled, + .accumulator_threshold = 0, + .irq_deadline_cycles = alert_handler_testutils_get_cycles_from_us(10) * + alert_handler_testutils_cycle_rescaling_factor(), + .escalation_phases = esc_phases, + .escalation_phases_len = ARRAYSIZE(esc_phases), + .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase3, + }}; + + dif_alert_handler_class_t classes[] = {kDifAlertHandlerClassA}; + dif_alert_handler_config_t config = { + .alerts = alerts, + .alert_classes = alert_classes, + .alerts_len = ARRAYSIZE(alerts), + .classes = classes, + .class_configs = class_config, + .classes_len = ARRAYSIZE(class_config), + .ping_timeout = 0, + }; + + alert_handler_testutils_configure_all(&alert_handler, config, + kDifToggleEnabled); + // Enables alert handler irq. + CHECK_DIF_OK(dif_alert_handler_irq_set_enabled( + &alert_handler, kDifAlertHandlerIrqClassa, kDifToggleEnabled)); +} + +/** + * Execute the aon timer interrupt test. + */ +static void config_escalate(dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr) { + uint64_t bark_cycles = + udiv64_slow(kWdogBarkMicros * kClockFreqAonHz, 1000000, NULL) * + alert_handler_testutils_cycle_rescaling_factor(); + uint64_t bite_cycles = + udiv64_slow(kWdogBiteMicros * kClockFreqAonHz, 1000000, NULL) * + alert_handler_testutils_cycle_rescaling_factor(); + + CHECK(bite_cycles < UINT32_MAX, + "The value %u can't fit into the 32 bits timer counter.", bite_cycles); + + LOG_INFO( + "Wdog will bark after %u/%u us/cycles and bite after %u/%u us/cycles", + (uint32_t)kWdogBarkMicros, (uint32_t)bark_cycles, + (uint32_t)kWdogBiteMicros, (uint32_t)bite_cycles); + + // Setup the wdog bark and bite timeouts. + aon_timer_testutils_watchdog_config(aon_timer, bark_cycles, bite_cycles, + false); + + // Trigger the alert handler to escalate. + dif_pwrmgr_alert_t alert = kDifPwrmgrAlertFatalFault; + CHECK_DIF_OK(dif_pwrmgr_alert_force(pwrmgr, alert)); +} + +/** + * Configure the sysrst. + */ +static void config_sysrst(const dif_pwrmgr_t *pwrmgr, + const dif_sysrst_ctrl_t *sysrst_ctrl_aon) { + LOG_INFO("sysrst enabled"); + + // Set sysrst as a reset source. + CHECK_DIF_OK(dif_pwrmgr_set_request_sources(pwrmgr, kDifPwrmgrReqTypeReset, + kDifPwrmgrResetRequestSourceOne, + kDifToggleEnabled)); + LOG_INFO("Reset Request SourceOne is set"); + + // Configure sysrst key combo + // reset pulse : 50 us + // detect durration : 50 us + + dif_sysrst_ctrl_key_combo_config_t sysrst_ctrl_key_combo_config = { + .keys = kDifSysrstCtrlKeyAll, + .detection_time_threshold = 10, + .actions = kDifSysrstCtrlKeyComboActionAll, + .embedded_controller_reset_duration = 10}; + + CHECK_DIF_OK(dif_sysrst_ctrl_key_combo_detect_configure( + sysrst_ctrl_aon, kDifSysrstCtrlKeyCombo0, sysrst_ctrl_key_combo_config)); + // Configure sysrst input change + // debounce durration : 100 us + dif_sysrst_ctrl_input_change_config_t sysrst_ctrl_input_change_config = { + .input_changes = kDifSysrstCtrlInputAll, .debounce_time_threshold = 20}; + + // Configure pinmux + dif_pinmux_t pinmux; + CHECK_DIF_OK(dif_pinmux_init( + mmio_region_from_addr(TOP_MATCHA_PINMUX_AON_BASE_ADDR), &pinmux)); + + CHECK_DIF_OK(dif_sysrst_ctrl_input_change_detect_configure( + sysrst_ctrl_aon, sysrst_ctrl_input_change_config)); + + CHECK_DIF_OK(dif_pinmux_input_select( + &pinmux, kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey0In, + kTopMatchaPinmuxInselIor13)); +} + +static void normal_sleep_sysrst(const dif_pwrmgr_t *pwrmgr) { + // Place device into low power and immediately wake. + dif_pwrmgr_domain_config_t config; + config = kDifPwrmgrDomainOptionUsbClockInLowPower | + kDifPwrmgrDomainOptionCoreClockInLowPower | + kDifPwrmgrDomainOptionIoClockInLowPower | + kDifPwrmgrDomainOptionMainPowerInLowPower; + pwrmgr_testutils_enable_low_power(pwrmgr, kDifPwrmgrWakeupRequestSourceOne, + config); + LOG_INFO("Normal sleep set for sysrst"); + + // Enter in low power mode. + wait_for_interrupt(); +} + +static void timer_on(uint32_t usec) { + busy_spin_micros(usec); + // If we arrive here the test must fail. + CHECK(false, "Timeout waiting for reset!"); +} + +/** + * Configure the wdog. + */ +static void config_wdog(const dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr, uint64_t bark_time_us, + uint64_t bite_time_us) { + uint32_t bark_cycles = + aon_timer_testutils_get_aon_cycles_from_us(bark_time_us); + uint32_t bite_cycles = + aon_timer_testutils_get_aon_cycles_from_us(bite_time_us); + + LOG_INFO("Wdog will bark after %u us and bite after %u us", + (uint32_t)bark_time_us, (uint32_t)bite_time_us); + // Setup the wdog bark and bite timeouts. + aon_timer_testutils_watchdog_config(aon_timer, bark_cycles, bite_cycles, + false); + // Set wdog as a reset source. + CHECK_DIF_OK(dif_pwrmgr_set_request_sources(pwrmgr, kDifPwrmgrReqTypeReset, + kDifPwrmgrResetRequestSourceTwo, + kDifToggleEnabled)); +} + +/** + * Execute the aon timer wdog bite reset test. + */ +static void wdog_bite_test(const dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr, uint64_t bark_time_us) { + uint64_t bite_time_us = bark_time_us * 2; + config_wdog(aon_timer, pwrmgr, bark_time_us, bite_time_us); + + // The `intr_state` takes 3 aon clock cycles to rise plus 2 extra cycles as a + // precaution. + uint32_t wait_us = + bark_time_us + + udiv64_slow(5 * 1000000 + kClockFreqAonHz - 1, kClockFreqAonHz, NULL); + + // Wait bark time and check that the bark interrupt requested. + busy_spin_micros(wait_us); + bool is_pending = false; + CHECK_DIF_OK(dif_aon_timer_irq_is_pending( + aon_timer, kDifAonTimerIrqWdogTimerBark, &is_pending)); + CHECK(is_pending, "Wdog bark irq did not rise after %u microseconds", + wait_us); + + // Wait for the remaining time to the wdog bite. + busy_spin_micros(wait_us); + // If we arrive here the test must fail. + CHECK(false, "Timeout waiting for Wdog bite reset!"); +} + +/** + * Execute the aon timer wdog bite reset during sleep test. + */ +static void sleep_wdog_bite_test(const dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr, + uint64_t bark_time_us) { + uint64_t bite_time_us = bark_time_us * 2; + config_wdog(aon_timer, pwrmgr, bark_time_us, bite_time_us); +} + +static void normal_sleep_wdog(const dif_pwrmgr_t *pwrmgr) { + // Place device into low power and immediately wake. + dif_pwrmgr_domain_config_t config; + config = kDifPwrmgrDomainOptionUsbClockInLowPower | + kDifPwrmgrDomainOptionCoreClockInLowPower | + kDifPwrmgrDomainOptionIoClockInLowPower | + kDifPwrmgrDomainOptionMainPowerInLowPower; + + // Enter in low power mode. + pwrmgr_testutils_enable_low_power(pwrmgr, kDifPwrmgrWakeupRequestSourceTwo, + config); + LOG_INFO("Normal sleep set for watchdog"); + wait_for_interrupt(); +} + +static void normal_sleep_por(const dif_pwrmgr_t *pwrmgr) { + // Set por as a reset source. + CHECK_DIF_OK(dif_pwrmgr_set_request_sources(pwrmgr, kDifPwrmgrReqTypeReset, + kDifPwrmgrResetRequestSourceTwo, + kDifToggleEnabled)); + + // Place device into low power and immediately wake. + dif_pwrmgr_domain_config_t config; + config = kDifPwrmgrDomainOptionUsbClockInLowPower | + kDifPwrmgrDomainOptionCoreClockInLowPower | + kDifPwrmgrDomainOptionIoClockInLowPower | + kDifPwrmgrDomainOptionMainPowerInLowPower; + + // Program the pwrmgr to go to deep sleep state (clocks off). + pwrmgr_testutils_enable_low_power( + pwrmgr, + (kDifPwrmgrWakeupRequestSourceOne | kDifPwrmgrWakeupRequestSourceTwo | + kDifPwrmgrWakeupRequestSourceThree | kDifPwrmgrWakeupRequestSourceFour | + kDifPwrmgrWakeupRequestSourceFive | kDifPwrmgrWakeupRequestSourceSix), + config); + LOG_INFO("ready for pad por"); + // Enter in low power mode. + wait_for_interrupt(); +} + +bool test_main(void) { + // Enable global and external IRQ at Ibex. + irq_global_ctrl(true); + irq_external_ctrl(true); + + init_peripherals(); + + // Enable all the AON interrupts used in this test. + rv_plic_testutils_irq_range_enable(&plic, kPlicTarget, + kTopMatchaPlicIrqIdAlertHandlerClassa, + kTopMatchaPlicIrqIdAlertHandlerClassd); + + alert_handler_config(); + + // First check the flash stored value + uint32_t event_idx = flash_ctrl_testutils_counter_get(0); + + // Enable flash access + flash_ctrl_testutils_default_region_access(&flash_ctrl, + /*rd_en*/ true, + /*prog_en*/ true, + /*erase_en*/ true, + /*scramble_en*/ false, + /*ecc_en*/ false, + /*he_en*/ false); + + // Increment flash counter to know where we are + flash_ctrl_testutils_counter_increment(&flash_ctrl, 0); + + LOG_INFO("Test round %d", event_idx); + LOG_INFO("RST_IDX[%d] = %d", event_idx, RST_IDX[event_idx]); + + // Check if there was a HW reset caused by expected cases + dif_rstmgr_reset_info_bitfield_t rst_info; + rst_info = rstmgr_testutils_reason_get(); + rstmgr_testutils_reason_clear(); + + CHECK(rst_info == kDifRstmgrResetInfoPor || + rst_info == kDifRstmgrResetInfoSysRstCtrl || + rst_info == kDifRstmgrResetInfoWatchdog || + rst_info == kDifRstmgrResetInfoEscalation || + rst_info == kDifRstmgrResetInfoLowPowerExit || + rst_info == (kDifRstmgrResetInfoSysRstCtrl | + kDifRstmgrResetInfoLowPowerExit) || + rst_info == + (kDifRstmgrResetInfoPor | kDifRstmgrResetInfoLowPowerExit) || + rst_info == (kDifRstmgrResetInfoWatchdog | + kDifRstmgrResetInfoLowPowerExit) || + rst_info == (kDifRstmgrResetInfoEscalation | + kDifRstmgrResetInfoLowPowerExit) || + rst_info == kDifRstmgrResetInfoSw, + "Wrong reset reason %02X", rst_info); + + switch (RST_IDX[event_idx]) { + case 0: + LOG_INFO("Booting and setting normal sleep followed by sysrst"); + config_sysrst(&pwrmgr, &sysrst_ctrl_aon); + normal_sleep_sysrst(&pwrmgr); + timer_on(kWdogBiteMicros); + break; + case 1: + LOG_INFO("Booting and setting normal sleep followed by hw por"); + normal_sleep_por(&pwrmgr); + timer_on(kWdogBiteMicros); + break; + case 2: + LOG_INFO( + "Booting and setting normal sleep mode followed for low_power " + "entry reset"); + LOG_INFO("Let SV wait timer reset"); + // actually the same test as normal sleep + watchdog + rstmgr_testutils_pre_reset(&rstmgr); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + normal_sleep_wdog(&pwrmgr); + timer_on(kEscalationPhase0MicrosCpu); + break; + case 3: + LOG_INFO( + "Booting and setting normal sleep followed by watchdog reset " + "combined " + "with sw_req"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + rstmgr_testutils_pre_reset(&rstmgr); + + // Assert reeset req + CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr)); + LOG_INFO("Device reset from sw"); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + normal_sleep_wdog(&pwrmgr); + timer_on(kEscalationPhase0MicrosCpu); + break; + case 4: + LOG_INFO("Booting and setting normal sleep followed by watchdog reset"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + rstmgr_testutils_pre_reset(&rstmgr); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + normal_sleep_wdog(&pwrmgr); + timer_on(kEscalationPhase0MicrosCpu); + break; + case 5: + LOG_INFO("Booting and running normal sleep followed by escalation reset"); + LOG_INFO("Let SV wait timer reset"); + config_escalate(&aon_timer, &pwrmgr); + timer_on(kEscalationPhase0MicrosCpu); + break; + case 6: + LOG_INFO("Last Booting"); + return true; + break; + default: + LOG_INFO("Booting for undefined case"); + } + + return false; +}
diff --git a/sw/device/tests/sim_dv/pwrmgr_random_sleep_all_reset_reqs_test.c b/sw/device/tests/sim_dv/pwrmgr_random_sleep_all_reset_reqs_test.c new file mode 100644 index 0000000..440a84b --- /dev/null +++ b/sw/device/tests/sim_dv/pwrmgr_random_sleep_all_reset_reqs_test.c
@@ -0,0 +1,617 @@ +// 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 <assert.h> +#include <limits.h> +#include <stdbool.h> +#include <stdint.h> + +#include "hw/top_matcha/sw/autogen/top_matcha.h" +#include "sw/device/lib/base/abs_mmio.h" +#include "sw/device/lib/base/math.h" +#include "sw/device/lib/base/mmio.h" +#include "sw/device/lib/dif/dif_alert_handler.h" +#include "sw/device/lib/dif/dif_aon_timer.h" +#include "sw/device/lib/dif/dif_flash_ctrl.h" +#include "sw/device/lib/dif/dif_pinmux.h" +#include "sw/device/lib/dif/dif_pwrmgr.h" +#include "sw/device/lib/dif/dif_rstmgr.h" +#include "sw/device/lib/dif/dif_rv_plic.h" +#include "sw/device/lib/dif/dif_rv_timer.h" +#include "sw/device/lib/dif/dif_sysrst_ctrl.h" +#include "sw/device/lib/runtime/irq.h" +#include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/alert_handler_testutils.h" +#include "sw/device/lib/testing/aon_timer_testutils.h" +#include "sw/device/lib/testing/flash_ctrl_testutils.h" +#include "sw/device/lib/testing/pwrmgr_testutils.h" +#include "sw/device/lib/testing/rstmgr_testutils.h" +#include "sw/device/lib/testing/rv_plic_testutils.h" +#include "sw/device/lib/testing/test_framework/FreeRTOSConfig.h" +#include "sw/device/lib/testing/test_framework/check.h" +#include "sw/device/lib/testing/test_framework/ottf_main.h" + +OTTF_DEFINE_TEST_CONFIG(); +static volatile const uint8_t RST_IDX[12] = {0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11}; +static const uint32_t kPlicTarget = kTopMatchaPlicTargetIbex0; + +/** + * Objects to access the peripherals used in this test via dif API. + */ +static dif_flash_ctrl_state_t flash_ctrl; +static dif_rv_plic_t plic; +static dif_alert_handler_t alert_handler; +static dif_aon_timer_t aon_timer; +static dif_pwrmgr_t pwrmgr; +static dif_sysrst_ctrl_t sysrst_ctrl_aon; +static dif_rstmgr_t rstmgr; + +/** + * Program the alert handler to escalate on alerts upto phase 2 (i.e. reset) but + * the phase 1 (i.e. wipe secrets) should occur and last during the time the + * wdog is programed to bark. + */ +enum { + kWdogBarkMicros = 3 * 100, // 300 us + kWdogBiteMicros = 4 * 100, // 400 us + kEscalationPhase0Micros = 1 * 100, // 100 us + // The cpu value is slightly larger as the busy_spin_micros + // routine cycle count comes out slightly smaller due to the + // fact that it does not divide by exactly 1M + // see sw/device/lib/runtime/hart.c + kEscalationPhase0MicrosCpu = kEscalationPhase0Micros + 20, // 120 us + kEscalationPhase1Micros = 5 * 100, // 500 us + kEscalationPhase2Micros = 50, // 50 us +}; + +static_assert( + kWdogBarkMicros < kWdogBiteMicros && + kWdogBarkMicros > kEscalationPhase0Micros && + kWdogBarkMicros < (kEscalationPhase0Micros + kEscalationPhase1Micros) && + kWdogBiteMicros < (kEscalationPhase0Micros + kEscalationPhase1Micros), + "The wdog bark and bite shall happens during the escalation phase 1"); + +/** + * External ISR. + * + * Handles all peripheral interrupts on Ibex. PLIC asserts an external interrupt + * line to the CPU, which results in a call to this OTTF ISR. This ISR + * overrides the default OTTF implementation. + */ +void ottf_external_isr(void) { + top_matcha_plic_peripheral_t peripheral; + dif_rv_plic_irq_id_t irq_id; + uint32_t irq = 0; + uint32_t alert = 0; + + CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic, kPlicTarget, &irq_id)); + + peripheral = (top_matcha_plic_peripheral_t) + top_matcha_plic_interrupt_for_peripheral[irq_id]; + + if (peripheral == kTopMatchaPlicPeripheralAonTimerAon) { + irq = + (dif_aon_timer_irq_t)(irq_id - + (dif_rv_plic_irq_id_t) + kTopMatchaPlicIrqIdAonTimerAonWkupTimerExpired); + + // Stops escalation process. + CHECK_DIF_OK(dif_alert_handler_escalation_clear(&alert_handler, + kDifAlertHandlerClassA)); + CHECK_DIF_OK(dif_aon_timer_irq_acknowledge(&aon_timer, irq)); + + CHECK(irq != kTopMatchaPlicIrqIdAonTimerAonWdogTimerBark, + "AON Timer Wdog should not bark"); + + } else if (peripheral == kTopMatchaPlicPeripheralAlertHandler) { + irq = (dif_rv_plic_irq_id_t)(irq_id - + (dif_rv_plic_irq_id_t) + kTopMatchaPlicIrqIdAlertHandlerClassa); + + CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(&alert_handler, alert)); + + dif_alert_handler_class_state_t state; + CHECK_DIF_OK(dif_alert_handler_get_class_state( + &alert_handler, kDifAlertHandlerClassA, &state)); + + CHECK(state == kDifAlertHandlerClassStatePhase0, "Wrong phase %d", state); + + CHECK_DIF_OK(dif_alert_handler_irq_acknowledge(&alert_handler, irq)); + } + + // Complete the IRQ by writing the IRQ source to the Ibex specific CC + // register. + CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic, kPlicTarget, irq_id)); +} + +/** + * Initialize the peripherals used in this test. + */ +void init_peripherals(void) { + // Initialize pwrmgr. + CHECK_DIF_OK(dif_pwrmgr_init( + mmio_region_from_addr(TOP_MATCHA_PWRMGR_AON_BASE_ADDR), &pwrmgr)); + + // Initialize sysrst_ctrl. + CHECK_DIF_OK(dif_sysrst_ctrl_init( + mmio_region_from_addr(TOP_MATCHA_SYSRST_CTRL_AON_BASE_ADDR), + &sysrst_ctrl_aon)); + + // Initialize rstmgr to check the reset reason. + CHECK_DIF_OK(dif_rstmgr_init( + mmio_region_from_addr(TOP_MATCHA_RSTMGR_AON_BASE_ADDR), &rstmgr)); + + // Initialize aon timer to use the wdog. + CHECK_DIF_OK(dif_aon_timer_init( + mmio_region_from_addr(TOP_MATCHA_AON_TIMER_AON_BASE_ADDR), &aon_timer)); + + // Initialize flash_ctrl + CHECK_DIF_OK(dif_flash_ctrl_init_state( + &flash_ctrl, + mmio_region_from_addr(TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR))); + + // Initialize plic. + CHECK_DIF_OK(dif_rv_plic_init( + mmio_region_from_addr(TOP_MATCHA_RV_PLIC_BASE_ADDR), &plic)); + + rv_plic_testutils_irq_range_enable( + &plic, kPlicTarget, kTopMatchaPlicIrqIdAonTimerAonWkupTimerExpired, + kTopMatchaPlicIrqIdAonTimerAonWdogTimerBark); + + // Initialize alert handler. + CHECK_DIF_OK(dif_alert_handler_init( + mmio_region_from_addr(TOP_MATCHA_ALERT_HANDLER_BASE_ADDR), + &alert_handler)); +} + +/** + * Program the alert handler to escalate on alerts upto phase 2 (i.e. reset) but + * the phase 1 (i.e. wipe secrets) should occur and last during the time the + * wdog is programed to bark. + */ +static void alert_handler_config(void) { + dif_alert_handler_alert_t alerts[] = {kTopMatchaAlertIdPwrmgrAonFatalFault}; + dif_alert_handler_class_t alert_classes[] = {kDifAlertHandlerClassA}; + + dif_alert_handler_escalation_phase_t esc_phases[] = { + {.phase = kDifAlertHandlerClassStatePhase0, + .signal = 0, + .duration_cycles = + alert_handler_testutils_get_cycles_from_us(kEscalationPhase0Micros) * + alert_handler_testutils_cycle_rescaling_factor()}, + {.phase = kDifAlertHandlerClassStatePhase1, + .signal = 1, + .duration_cycles = + alert_handler_testutils_get_cycles_from_us(kEscalationPhase1Micros) * + alert_handler_testutils_cycle_rescaling_factor()}, + {.phase = kDifAlertHandlerClassStatePhase2, + .signal = 3, + .duration_cycles = + alert_handler_testutils_get_cycles_from_us(kEscalationPhase2Micros) * + alert_handler_testutils_cycle_rescaling_factor()}}; + + dif_alert_handler_class_config_t class_config[] = {{ + .auto_lock_accumulation_counter = kDifToggleDisabled, + .accumulator_threshold = 0, + .irq_deadline_cycles = alert_handler_testutils_get_cycles_from_us(10) * + alert_handler_testutils_cycle_rescaling_factor(), + .escalation_phases = esc_phases, + .escalation_phases_len = ARRAYSIZE(esc_phases), + .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase3, + }}; + + dif_alert_handler_class_t classes[] = {kDifAlertHandlerClassA}; + dif_alert_handler_config_t config = { + .alerts = alerts, + .alert_classes = alert_classes, + .alerts_len = ARRAYSIZE(alerts), + .classes = classes, + .class_configs = class_config, + .classes_len = ARRAYSIZE(class_config), + .ping_timeout = 0, + }; + + alert_handler_testutils_configure_all(&alert_handler, config, + kDifToggleEnabled); + // Enables alert handler irq. + CHECK_DIF_OK(dif_alert_handler_irq_set_enabled( + &alert_handler, kDifAlertHandlerIrqClassa, kDifToggleEnabled)); +} + +/** + * Execute the aon timer interrupt test. + */ +static void config_escalate(dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr) { + uint64_t bark_cycles = + udiv64_slow(kWdogBarkMicros * kClockFreqAonHz, 1000000, NULL) * + alert_handler_testutils_cycle_rescaling_factor(); + uint64_t bite_cycles = + udiv64_slow(kWdogBiteMicros * kClockFreqAonHz, 1000000, NULL) * + alert_handler_testutils_cycle_rescaling_factor(); + + CHECK(bite_cycles < UINT32_MAX, + "The value %u can't fit into the 32 bits timer counter.", bite_cycles); + + LOG_INFO( + "Wdog will bark after %u/%u us/cycles and bite after %u/%u us/cycles", + (uint32_t)kWdogBarkMicros, (uint32_t)bark_cycles, + (uint32_t)kWdogBiteMicros, (uint32_t)bite_cycles); + + // Setup the wdog bark and bite timeouts. + aon_timer_testutils_watchdog_config(aon_timer, bark_cycles, bite_cycles, + false); + + // Trigger the alert handler to escalate. + dif_pwrmgr_alert_t alert = kDifPwrmgrAlertFatalFault; + CHECK_DIF_OK(dif_pwrmgr_alert_force(pwrmgr, alert)); +} + +/** + * Configure the sysrst. + */ +static void config_sysrst(const dif_pwrmgr_t *pwrmgr, + const dif_sysrst_ctrl_t *sysrst_ctrl_aon) { + LOG_INFO("sysrst enabled"); + + // Set sysrst as a reset source. + CHECK_DIF_OK(dif_pwrmgr_set_request_sources(pwrmgr, kDifPwrmgrReqTypeReset, + kDifPwrmgrResetRequestSourceOne, + kDifToggleEnabled)); + LOG_INFO("Reset Request SourceOne is set"); + + // Configure sysrst key combo + // reset pulse : 50 us + // detect durration : 50 us + + dif_sysrst_ctrl_key_combo_config_t sysrst_ctrl_key_combo_config = { + .keys = kDifSysrstCtrlKeyAll, + .detection_time_threshold = 10, + .actions = kDifSysrstCtrlKeyComboActionAll, + .embedded_controller_reset_duration = 10}; + + CHECK_DIF_OK(dif_sysrst_ctrl_key_combo_detect_configure( + sysrst_ctrl_aon, kDifSysrstCtrlKeyCombo0, sysrst_ctrl_key_combo_config)); + // Configure sysrst input change + // debounce durration : 100 us + dif_sysrst_ctrl_input_change_config_t sysrst_ctrl_input_change_config = { + .input_changes = kDifSysrstCtrlInputAll, .debounce_time_threshold = 20}; + + // Configure pinmux + dif_pinmux_t pinmux; + CHECK_DIF_OK(dif_pinmux_init( + mmio_region_from_addr(TOP_MATCHA_PINMUX_AON_BASE_ADDR), &pinmux)); + + CHECK_DIF_OK(dif_sysrst_ctrl_input_change_detect_configure( + sysrst_ctrl_aon, sysrst_ctrl_input_change_config)); + + CHECK_DIF_OK(dif_pinmux_input_select( + &pinmux, kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey0In, + kTopMatchaPinmuxInselIor13)); +} + +static void low_power_sysrst(const dif_pwrmgr_t *pwrmgr) { + // Program the pwrmgr to go to deep sleep state (clocks off). + pwrmgr_testutils_enable_low_power(pwrmgr, kDifPwrmgrWakeupRequestSourceOne, + 0); + // Enter in low power mode. + wait_for_interrupt(); +} + +static void normal_sleep_sysrst(const dif_pwrmgr_t *pwrmgr) { + // Place device into low power and immediately wake. + dif_pwrmgr_domain_config_t config; + config = kDifPwrmgrDomainOptionUsbClockInLowPower | + kDifPwrmgrDomainOptionCoreClockInLowPower | + kDifPwrmgrDomainOptionIoClockInLowPower | + kDifPwrmgrDomainOptionMainPowerInLowPower; + pwrmgr_testutils_enable_low_power(pwrmgr, kDifPwrmgrWakeupRequestSourceOne, + config); + // Enter in low power mode. + wait_for_interrupt(); +} + +static void timer_on(uint32_t usec) { + busy_spin_micros(usec); + // If we arrive here the test must fail. + CHECK(false, "Timeout waiting for reset!"); +} + +/** + * Configure the wdog. + */ +static void config_wdog(const dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr, uint64_t bark_time_us, + uint64_t bite_time_us) { + uint32_t bark_cycles = + aon_timer_testutils_get_aon_cycles_from_us(bark_time_us); + uint32_t bite_cycles = + aon_timer_testutils_get_aon_cycles_from_us(bite_time_us); + + LOG_INFO("Wdog will bark after %u us and bite after %u us", + (uint32_t)bark_time_us, (uint32_t)bite_time_us); + // Setup the wdog bark and bite timeouts. + + aon_timer_testutils_watchdog_config(aon_timer, bark_cycles, bite_cycles, + false); + // Set wdog as a reset source. + CHECK_DIF_OK(dif_pwrmgr_set_request_sources(pwrmgr, kDifPwrmgrReqTypeReset, + kDifPwrmgrResetRequestSourceTwo, + kDifToggleEnabled)); +} + +/** + * Execute the aon timer wdog bite reset test. + */ +static void wdog_bite_test(const dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr, uint64_t bark_time_us) { + uint64_t bite_time_us = bark_time_us * 2; + config_wdog(aon_timer, pwrmgr, bark_time_us, bite_time_us); + + // The `intr_state` takes 3 aon clock cycles to rise plus 2 extra cycles as a + // precaution. + uint32_t wait_us = + bark_time_us + + udiv64_slow(5 * 1000000 + kClockFreqAonHz - 1, kClockFreqAonHz, NULL); + + // Wait bark time and check that the bark interrupt requested. + busy_spin_micros(wait_us); + bool is_pending = false; + CHECK_DIF_OK(dif_aon_timer_irq_is_pending( + aon_timer, kDifAonTimerIrqWdogTimerBark, &is_pending)); + CHECK(is_pending, "Wdog bark irq did not rise after %u microseconds", + wait_us); + + // Wait for the remaining time to the wdog bite. + busy_spin_micros(wait_us); + // If we arrive here the test must fail. + CHECK(false, "Timeout waiting for Wdog bite reset!"); +} + +/** + * Execute the aon timer wdog bite reset during sleep test. + */ +static void sleep_wdog_bite_test(const dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr, + uint64_t bark_time_us) { + uint64_t bite_time_us = bark_time_us * 2; + config_wdog(aon_timer, pwrmgr, bark_time_us, bite_time_us); +} + +static void low_power_wdog(const dif_pwrmgr_t *pwrmgr) { + // Program the pwrmgr to go to deep sleep state (clocks off). + // Enter in low power mode. + pwrmgr_testutils_enable_low_power(pwrmgr, kDifPwrmgrWakeupRequestSourceTwo, + 0); + LOG_INFO("Low power set for watch dog"); + wait_for_interrupt(); + // If we arrive here the test must fail. + CHECK(false, "Fail to enter in low power mode!"); +} + +static void normal_sleep_wdog(const dif_pwrmgr_t *pwrmgr) { + // Place device into low power and immediately wake. + dif_pwrmgr_domain_config_t config; + config = kDifPwrmgrDomainOptionUsbClockInLowPower | + kDifPwrmgrDomainOptionCoreClockInLowPower | + kDifPwrmgrDomainOptionIoClockInLowPower | + kDifPwrmgrDomainOptionMainPowerInLowPower; + + // Enter in low power mode. + pwrmgr_testutils_enable_low_power(pwrmgr, kDifPwrmgrWakeupRequestSourceTwo, + config); + LOG_INFO("Normal sleep set for watchdog"); + wait_for_interrupt(); +} + +static void low_power_por(const dif_pwrmgr_t *pwrmgr) { + // Set por as a reset source. + CHECK_DIF_OK(dif_pwrmgr_set_request_sources(pwrmgr, kDifPwrmgrReqTypeReset, + kDifPwrmgrResetRequestSourceTwo, + kDifToggleEnabled)); + + // Program the pwrmgr to go to deep sleep state (clocks off). + pwrmgr_testutils_enable_low_power( + pwrmgr, + (kDifPwrmgrWakeupRequestSourceOne | kDifPwrmgrWakeupRequestSourceTwo | + kDifPwrmgrWakeupRequestSourceThree | kDifPwrmgrWakeupRequestSourceFour | + kDifPwrmgrWakeupRequestSourceFive | kDifPwrmgrWakeupRequestSourceSix), + 0); + // Enter in low power mode. + wait_for_interrupt(); + // If we arrive here the test must fail. + CHECK(false, "Fail to enter in low power mode!"); +} + +static void normal_sleep_por(const dif_pwrmgr_t *pwrmgr) { + // Set por as a reset source. + CHECK_DIF_OK(dif_pwrmgr_set_request_sources(pwrmgr, kDifPwrmgrReqTypeReset, + kDifPwrmgrResetRequestSourceTwo, + kDifToggleEnabled)); + + // Place device into low power and immediately wake. + dif_pwrmgr_domain_config_t config; + config = kDifPwrmgrDomainOptionUsbClockInLowPower | + kDifPwrmgrDomainOptionCoreClockInLowPower | + kDifPwrmgrDomainOptionIoClockInLowPower | + kDifPwrmgrDomainOptionMainPowerInLowPower; + + // Program the pwrmgr to go to deep sleep state (clocks off). + pwrmgr_testutils_enable_low_power( + pwrmgr, + (kDifPwrmgrWakeupRequestSourceOne | kDifPwrmgrWakeupRequestSourceTwo | + kDifPwrmgrWakeupRequestSourceThree | kDifPwrmgrWakeupRequestSourceFour | + kDifPwrmgrWakeupRequestSourceFive | kDifPwrmgrWakeupRequestSourceSix), + config); + // Enter in low power mode. + wait_for_interrupt(); +} + +bool test_main(void) { + // Enable global and external IRQ at Ibex. + irq_global_ctrl(true); + irq_external_ctrl(true); + + init_peripherals(); + + // Enable all the AON interrupts used in this test. + rv_plic_testutils_irq_range_enable(&plic, kPlicTarget, + kTopMatchaPlicIrqIdAlertHandlerClassa, + kTopMatchaPlicIrqIdAlertHandlerClassd); + + alert_handler_config(); + + // First check the flash stored value + uint32_t event_idx = flash_ctrl_testutils_counter_get(0); + + // Enable flash access + flash_ctrl_testutils_default_region_access(&flash_ctrl, + /*rd_en*/ true, + /*prog_en*/ true, + /*erase_en*/ true, + /*scramble_en*/ false, + /*ecc_en*/ false, + /*he_en*/ false); + + // Increment flash counter to know where we are + flash_ctrl_testutils_counter_increment(&flash_ctrl, 0); + + LOG_INFO("Test round %d", event_idx); + LOG_INFO("RST_IDX[%d] = %d", event_idx, RST_IDX[event_idx]); + + // Check if there was a HW reset caused by expected cases + dif_rstmgr_reset_info_bitfield_t rst_info; + rst_info = rstmgr_testutils_reason_get(); + rstmgr_testutils_reason_clear(); + + CHECK(rst_info == kDifRstmgrResetInfoPor || + rst_info == kDifRstmgrResetInfoSysRstCtrl || + rst_info == kDifRstmgrResetInfoWatchdog || + rst_info == kDifRstmgrResetInfoEscalation || + rst_info == kDifRstmgrResetInfoLowPowerExit || + rst_info == (kDifRstmgrResetInfoSysRstCtrl | + kDifRstmgrResetInfoLowPowerExit) || + rst_info == + (kDifRstmgrResetInfoPor | kDifRstmgrResetInfoLowPowerExit) || + rst_info == (kDifRstmgrResetInfoWatchdog | + kDifRstmgrResetInfoLowPowerExit) || + rst_info == (kDifRstmgrResetInfoEscalation | + kDifRstmgrResetInfoLowPowerExit) || + rst_info == kDifRstmgrResetInfoSw, + "Wrong reset reason %02X", rst_info); + + LOG_INFO("New reset event"); + + switch (RST_IDX[event_idx] / 2) { + case 0: + if (RST_IDX[event_idx] % 2) { + LOG_INFO("Booting and setting normal sleep followed by sysrst"); + config_sysrst(&pwrmgr, &sysrst_ctrl_aon); + normal_sleep_sysrst(&pwrmgr); + timer_on(kWdogBiteMicros); + } else { + LOG_INFO("Booting and setting deep sleep followed by sysrst"); + config_sysrst(&pwrmgr, &sysrst_ctrl_aon); + low_power_sysrst(&pwrmgr); + } + break; + case 1: + if (RST_IDX[event_idx] % 2) { + LOG_INFO("Booting and setting normal sleep followed by hw por"); + normal_sleep_por(&pwrmgr); + timer_on(kWdogBiteMicros); + } else { + LOG_INFO("Booting and setting deep sleep followed by hw por"); + low_power_por(&pwrmgr); + } + break; + case 2: + if (RST_IDX[event_idx] % 2) { + LOG_INFO( + "Booting and setting normal sleep mode followed for low_power " + "entry reset"); + LOG_INFO("Let SV wait timer reset"); + // actually the same test as normal sleep + watchdog + rstmgr_testutils_pre_reset(&rstmgr); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + normal_sleep_wdog(&pwrmgr); + timer_on(kEscalationPhase0MicrosCpu); + } else { + LOG_INFO( + "Booting and setting deep sleep mode followed for low_power entry " + "reset"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + // actually the same test as deep sleep + watchdog + rstmgr_testutils_pre_reset(&rstmgr); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + low_power_wdog(&pwrmgr); + } + break; + + case 3: + if (RST_IDX[event_idx] % 2) { + LOG_INFO( + "Booting and setting normal sleep followed by watchdog reset " + "combined " + "with sw_req"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + rstmgr_testutils_pre_reset(&rstmgr); + CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr)); + LOG_INFO("Device reset from sw"); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + normal_sleep_wdog(&pwrmgr); + timer_on(kEscalationPhase0MicrosCpu); + } else { + LOG_INFO( + "Booting and setting deep sleep followed by watchdog reset " + "combined " + "with sw_req"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + rstmgr_testutils_pre_reset(&rstmgr); + CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr)); + LOG_INFO("Device reset from sw"); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + low_power_wdog(&pwrmgr); + } + break; + case 4: + if (RST_IDX[event_idx] % 2) { + LOG_INFO("Booting and setting normal sleep followed by watchdog reset"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + rstmgr_testutils_pre_reset(&rstmgr); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + normal_sleep_wdog(&pwrmgr); + timer_on(kEscalationPhase0MicrosCpu); + } else { + LOG_INFO("Booting and setting deep sleep followed by watchdog reset"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + rstmgr_testutils_pre_reset(&rstmgr); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + low_power_wdog(&pwrmgr); + } + break; + case 5: + if (RST_IDX[event_idx] % 2) { + LOG_INFO("Last Booting"); + + return true; + } else { + LOG_INFO( + "Booting and running normal sleep followed by escalation reset"); + config_escalate(&aon_timer, &pwrmgr); + timer_on(kEscalationPhase0MicrosCpu); + } + break; + default: + LOG_INFO("Booting for undefined case"); + } + return false; +}
diff --git a/sw/device/tests/sim_dv/pwrmgr_random_sleep_power_glitch_reset_test.c b/sw/device/tests/sim_dv/pwrmgr_random_sleep_power_glitch_reset_test.c new file mode 100644 index 0000000..3f16463 --- /dev/null +++ b/sw/device/tests/sim_dv/pwrmgr_random_sleep_power_glitch_reset_test.c
@@ -0,0 +1,577 @@ +// 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 <assert.h> +#include <limits.h> +#include <stdbool.h> +#include <stdint.h> + +#include "hw/top_matcha/sw/autogen/top_matcha.h" +#include "sw/device/lib/base/abs_mmio.h" +#include "sw/device/lib/base/math.h" +#include "sw/device/lib/base/mmio.h" +#include "sw/device/lib/dif/dif_alert_handler.h" +#include "sw/device/lib/dif/dif_aon_timer.h" +#include "sw/device/lib/dif/dif_flash_ctrl.h" +#include "sw/device/lib/dif/dif_pinmux.h" +#include "sw/device/lib/dif/dif_pwrmgr.h" +#include "sw/device/lib/dif/dif_rstmgr.h" +#include "sw/device/lib/dif/dif_rv_plic.h" +#include "sw/device/lib/dif/dif_rv_timer.h" +#include "sw/device/lib/dif/dif_sysrst_ctrl.h" +#include "sw/device/lib/runtime/irq.h" +#include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/alert_handler_testutils.h" +#include "sw/device/lib/testing/aon_timer_testutils.h" +#include "sw/device/lib/testing/flash_ctrl_testutils.h" +#include "sw/device/lib/testing/pwrmgr_testutils.h" +#include "sw/device/lib/testing/rstmgr_testutils.h" +#include "sw/device/lib/testing/rv_plic_testutils.h" +#include "sw/device/lib/testing/test_framework/FreeRTOSConfig.h" +#include "sw/device/lib/testing/test_framework/check.h" +#include "sw/device/lib/testing/test_framework/ottf_main.h" + +OTTF_DEFINE_TEST_CONFIG(); +static volatile const uint8_t RST_IDX[12] = {0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11}; +static const uint32_t kPlicTarget = kTopMatchaPlicTargetIbex0; + +/** + * Objects to access the peripherals used in this test via dif API. + */ +static dif_flash_ctrl_state_t flash_ctrl; +static dif_rv_plic_t plic; +static dif_alert_handler_t alert_handler; +static dif_aon_timer_t aon_timer; +static dif_pwrmgr_t pwrmgr; +static dif_rstmgr_t rstmgr; + +/** + * Program the alert handler to escalate on alerts upto phase 2 (i.e. reset) but + * the phase 1 (i.e. wipe secrets) should occur and last during the time the + * wdog is programed to bark. + */ +enum { + kWdogBarkMicros = 3 * 100, // 300 us + kWdogBiteMicros = 4 * 100, // 400 us + kEscalationPhase0Micros = 1 * 100, // 100 us + // The cpu value is slightly larger as the busy_spin_micros + // routine cycle count comes out slightly smaller due to the + // fact that it does not divide by exactly 1M + // see sw/device/lib/runtime/hart.c + kEscalationPhase0MicrosCpu = kEscalationPhase0Micros + 20, // 120 us + kEscalationPhase1Micros = 5 * 100, // 500 us + kEscalationPhase2Micros = 50, // 50 us +}; + +static_assert( + kWdogBarkMicros < kWdogBiteMicros && + kWdogBarkMicros > kEscalationPhase0Micros && + kWdogBarkMicros < (kEscalationPhase0Micros + kEscalationPhase1Micros) && + kWdogBiteMicros < (kEscalationPhase0Micros + kEscalationPhase1Micros), + "The wdog bark and bite shall happens during the escalation phase 1"); + +/** + * External ISR. + * + * Handles all peripheral interrupts on Ibex. PLIC asserts an external interrupt + * line to the CPU, which results in a call to this OTTF ISR. This ISR + * overrides the default OTTF implementation. + */ +void ottf_external_isr(void) { + top_matcha_plic_peripheral_t peripheral; + dif_rv_plic_irq_id_t irq_id; + uint32_t irq = 0; + uint32_t alert = 0; + + CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic, kPlicTarget, &irq_id)); + + peripheral = (top_matcha_plic_peripheral_t) + top_matcha_plic_interrupt_for_peripheral[irq_id]; + + if (peripheral == kTopMatchaPlicPeripheralAonTimerAon) { + irq = + (dif_aon_timer_irq_t)(irq_id - + (dif_rv_plic_irq_id_t) + kTopMatchaPlicIrqIdAonTimerAonWkupTimerExpired); + + // Stops escalation process. + CHECK_DIF_OK(dif_alert_handler_escalation_clear(&alert_handler, + kDifAlertHandlerClassA)); + CHECK_DIF_OK(dif_aon_timer_irq_acknowledge(&aon_timer, irq)); + + CHECK(irq != kTopMatchaPlicIrqIdAonTimerAonWdogTimerBark, + "AON Timer Wdog should not bark"); + + } else if (peripheral == kTopMatchaPlicPeripheralAlertHandler) { + irq = (dif_rv_plic_irq_id_t)(irq_id - + (dif_rv_plic_irq_id_t) + kTopMatchaPlicIrqIdAlertHandlerClassa); + + CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(&alert_handler, alert)); + + dif_alert_handler_class_state_t state; + CHECK_DIF_OK(dif_alert_handler_get_class_state( + &alert_handler, kDifAlertHandlerClassA, &state)); + + CHECK(state == kDifAlertHandlerClassStatePhase0, "Wrong phase %d", state); + + CHECK_DIF_OK(dif_alert_handler_irq_acknowledge(&alert_handler, irq)); + } + + // Complete the IRQ by writing the IRQ source to the Ibex specific CC + // register. + CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic, kPlicTarget, irq_id)); +} + +/** + * Initialize the peripherals used in this test. + */ +void init_peripherals(void) { + // Initialize pwrmgr. + CHECK_DIF_OK(dif_pwrmgr_init( + mmio_region_from_addr(TOP_MATCHA_PWRMGR_AON_BASE_ADDR), &pwrmgr)); + + // Initialize rstmgr to check the reset reason. + CHECK_DIF_OK(dif_rstmgr_init( + mmio_region_from_addr(TOP_MATCHA_RSTMGR_AON_BASE_ADDR), &rstmgr)); + + // Initialize aon timer to use the wdog. + CHECK_DIF_OK(dif_aon_timer_init( + mmio_region_from_addr(TOP_MATCHA_AON_TIMER_AON_BASE_ADDR), &aon_timer)); + + // Initialize flash_ctrl + CHECK_DIF_OK(dif_flash_ctrl_init_state( + &flash_ctrl, + mmio_region_from_addr(TOP_MATCHA_FLASH_CTRL_CORE_BASE_ADDR))); + + // Initialize plic. + CHECK_DIF_OK(dif_rv_plic_init( + mmio_region_from_addr(TOP_MATCHA_RV_PLIC_BASE_ADDR), &plic)); + + rv_plic_testutils_irq_range_enable( + &plic, kPlicTarget, kTopMatchaPlicIrqIdAonTimerAonWkupTimerExpired, + kTopMatchaPlicIrqIdAonTimerAonWdogTimerBark); + + // Initialize alert handler. + CHECK_DIF_OK(dif_alert_handler_init( + mmio_region_from_addr(TOP_MATCHA_ALERT_HANDLER_BASE_ADDR), + &alert_handler)); +} + +/** + * Program the alert handler to escalate on alerts upto phase 2 (i.e. reset) but + * the phase 1 (i.e. wipe secrets) should occur and last during the time the + * wdog is programed to bark. + */ +static void alert_handler_config(void) { + dif_alert_handler_alert_t alerts[] = {kTopMatchaAlertIdPwrmgrAonFatalFault}; + dif_alert_handler_class_t alert_classes[] = {kDifAlertHandlerClassA}; + + dif_alert_handler_escalation_phase_t esc_phases[] = { + {.phase = kDifAlertHandlerClassStatePhase0, + .signal = 0, + .duration_cycles = + alert_handler_testutils_get_cycles_from_us(kEscalationPhase0Micros) * + alert_handler_testutils_cycle_rescaling_factor()}, + {.phase = kDifAlertHandlerClassStatePhase1, + .signal = 1, + .duration_cycles = + alert_handler_testutils_get_cycles_from_us(kEscalationPhase1Micros) * + alert_handler_testutils_cycle_rescaling_factor()}, + {.phase = kDifAlertHandlerClassStatePhase2, + .signal = 3, + .duration_cycles = + alert_handler_testutils_get_cycles_from_us(kEscalationPhase2Micros) * + alert_handler_testutils_cycle_rescaling_factor()}}; + + dif_alert_handler_class_config_t class_config[] = {{ + .auto_lock_accumulation_counter = kDifToggleDisabled, + .accumulator_threshold = 0, + .irq_deadline_cycles = + alert_handler_testutils_get_cycles_from_us(kEscalationPhase0Micros) * + alert_handler_testutils_cycle_rescaling_factor(), + .escalation_phases = esc_phases, + .escalation_phases_len = ARRAYSIZE(esc_phases), + .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase3, + }}; + + dif_alert_handler_class_t classes[] = {kDifAlertHandlerClassA}; + dif_alert_handler_config_t config = { + .alerts = alerts, + .alert_classes = alert_classes, + .alerts_len = ARRAYSIZE(alerts), + .classes = classes, + .class_configs = class_config, + .classes_len = ARRAYSIZE(class_config), + .ping_timeout = 0, + }; + + alert_handler_testutils_configure_all(&alert_handler, config, + kDifToggleEnabled); + // Enables alert handler irq. + CHECK_DIF_OK(dif_alert_handler_irq_set_enabled( + &alert_handler, kDifAlertHandlerIrqClassa, kDifToggleEnabled)); +} + +/** + * Execute the aon timer interrupt test. + */ +static void config_escalate(dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr) { + uint64_t bark_cycles = + aon_timer_testutils_get_aon_cycles_from_us(kWdogBarkMicros) * + alert_handler_testutils_cycle_rescaling_factor(); + uint64_t bite_cycles = + aon_timer_testutils_get_aon_cycles_from_us(kWdogBiteMicros) * + alert_handler_testutils_cycle_rescaling_factor(); + + LOG_INFO( + "Wdog will bark after %u/%u us/cycles and bite after %u/%u us/cycles", + (uint32_t)kWdogBarkMicros, (uint32_t)bark_cycles, + (uint32_t)kWdogBiteMicros, (uint32_t)bite_cycles); + + // Setup the wdog bark and bite timeouts. + aon_timer_testutils_watchdog_config(aon_timer, bark_cycles, bite_cycles, + false); + + // Trigger the alert handler to escalate. + dif_pwrmgr_alert_t alert = kDifPwrmgrAlertFatalFault; + CHECK_DIF_OK(dif_pwrmgr_alert_force(pwrmgr, alert)); +} + +static void low_power_glitch_reset(const dif_pwrmgr_t *pwrmgr) { + // Program the pwrmgr to go to deep sleep state (clocks off). + pwrmgr_testutils_enable_low_power(pwrmgr, kDifPwrmgrWakeupRequestSourceFive, + 0); + // Enter in low power mode. + wait_for_interrupt(); +} + +static void normal_sleep_glitch_reset(const dif_pwrmgr_t *pwrmgr) { + // Place device into normal (shallow) power + dif_pwrmgr_domain_config_t config; + config = kDifPwrmgrDomainOptionUsbClockInLowPower | + kDifPwrmgrDomainOptionCoreClockInLowPower | + kDifPwrmgrDomainOptionIoClockInLowPower | + kDifPwrmgrDomainOptionMainPowerInLowPower; + pwrmgr_testutils_enable_low_power(pwrmgr, kDifPwrmgrWakeupRequestSourceFive, + config); + // Enter in low power mode. + wait_for_interrupt(); +} + +static void timer_on(uint32_t usec) { + busy_spin_micros(usec); + // If we arrive here the test must fail. + CHECK(false, "Timeout waiting for reset!"); +} + +/** + * Configure the wdog. + */ +static void config_wdog(const dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr, uint64_t bark_time_us, + uint64_t bite_time_us) { + uint32_t bark_cycles = + aon_timer_testutils_get_aon_cycles_from_us(bark_time_us); + uint32_t bite_cycles = + aon_timer_testutils_get_aon_cycles_from_us(bite_time_us); + + LOG_INFO("Wdog will bark after %u us and bite after %u us", + (uint32_t)bark_time_us, (uint32_t)bite_time_us); + // Setup the wdog bark and bite timeouts. + + aon_timer_testutils_watchdog_config(aon_timer, bark_cycles, bite_cycles, + false); + // Set wdog as a reset source. + CHECK_DIF_OK(dif_pwrmgr_set_request_sources(pwrmgr, kDifPwrmgrReqTypeReset, + kDifPwrmgrResetRequestSourceTwo, + kDifToggleEnabled)); +} + +/** + * Execute the aon timer wdog bite reset test. + */ +static void wdog_bite_test(const dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr, uint64_t bark_time_us) { + uint64_t bite_time_us = bark_time_us * 2; + config_wdog(aon_timer, pwrmgr, bark_time_us, bite_time_us); + + // The `intr_state` takes 3 aon clock cycles to rise plus 2 extra cycles as a + // precaution. + uint32_t wait_us = + bark_time_us + + alert_handler_testutils_get_cycles_from_us(kEscalationPhase0Micros) * + alert_handler_testutils_cycle_rescaling_factor(); + + // Wait bark time and check that the bark interrupt requested. + busy_spin_micros(wait_us); + bool is_pending = false; + CHECK_DIF_OK(dif_aon_timer_irq_is_pending( + aon_timer, kDifAonTimerIrqWdogTimerBark, &is_pending)); + CHECK(is_pending, "Wdog bark irq did not rise after %u microseconds", + wait_us); + + // Wait for the remaining time to the wdog bite. + busy_spin_micros(wait_us); + // If we arrive here the test must fail. + CHECK(false, "Timeout waiting for Wdog bite reset!"); +} + +/** + * Execute the aon timer wdog bite reset during sleep test. + */ +static void sleep_wdog_bite_test(const dif_aon_timer_t *aon_timer, + const dif_pwrmgr_t *pwrmgr, + uint64_t bark_time_us) { + uint64_t bite_time_us = bark_time_us * 2; + config_wdog(aon_timer, pwrmgr, bark_time_us, bite_time_us); +} + +static void low_power_wdog(const dif_pwrmgr_t *pwrmgr) { + // Program the pwrmgr to go to deep sleep state (clocks off). + // Enter in low power mode. + pwrmgr_testutils_enable_low_power(pwrmgr, kDifPwrmgrWakeupRequestSourceTwo, + 0); + LOG_INFO("Low power set for watch dog"); + wait_for_interrupt(); + // If we arrive here the test must fail. + CHECK(false, "Fail to enter in low power mode!"); +} + +static void normal_sleep_wdog(const dif_pwrmgr_t *pwrmgr) { + // Place device into low power and immediately wake. + dif_pwrmgr_domain_config_t config; + config = kDifPwrmgrDomainOptionUsbClockInLowPower | + kDifPwrmgrDomainOptionCoreClockInLowPower | + kDifPwrmgrDomainOptionIoClockInLowPower | + kDifPwrmgrDomainOptionMainPowerInLowPower; + + // Enter in low power mode. + pwrmgr_testutils_enable_low_power(pwrmgr, kDifPwrmgrWakeupRequestSourceTwo, + config); + LOG_INFO("Normal sleep set for watchdog"); + wait_for_interrupt(); +} + +static void low_power_por(const dif_pwrmgr_t *pwrmgr) { + // Set por as a reset source. + CHECK_DIF_OK(dif_pwrmgr_set_request_sources(pwrmgr, kDifPwrmgrReqTypeReset, + kDifPwrmgrResetRequestSourceTwo, + kDifToggleEnabled)); + + // Program the pwrmgr to go to deep sleep state (clocks off). + pwrmgr_testutils_enable_low_power( + pwrmgr, + (kDifPwrmgrWakeupRequestSourceOne | kDifPwrmgrWakeupRequestSourceTwo | + kDifPwrmgrWakeupRequestSourceThree | kDifPwrmgrWakeupRequestSourceFour | + kDifPwrmgrWakeupRequestSourceFive | kDifPwrmgrWakeupRequestSourceSix), + 0); + // Enter in low power mode. + wait_for_interrupt(); + // If we arrive here the test must fail. + CHECK(false, "Fail to enter in low power mode!"); +} + +static void normal_sleep_por(const dif_pwrmgr_t *pwrmgr) { + // Set por as a reset source. + CHECK_DIF_OK(dif_pwrmgr_set_request_sources(pwrmgr, kDifPwrmgrReqTypeReset, + kDifPwrmgrResetRequestSourceTwo, + kDifToggleEnabled)); + + // Place device into low power and immediately wake. + dif_pwrmgr_domain_config_t config; + config = kDifPwrmgrDomainOptionUsbClockInLowPower | + kDifPwrmgrDomainOptionCoreClockInLowPower | + kDifPwrmgrDomainOptionIoClockInLowPower | + kDifPwrmgrDomainOptionMainPowerInLowPower; + + // Program the pwrmgr to go to swallow sleep state (clocks on). + pwrmgr_testutils_enable_low_power( + pwrmgr, + (kDifPwrmgrWakeupRequestSourceOne | kDifPwrmgrWakeupRequestSourceTwo | + kDifPwrmgrWakeupRequestSourceThree | kDifPwrmgrWakeupRequestSourceFour | + kDifPwrmgrWakeupRequestSourceFive | kDifPwrmgrWakeupRequestSourceSix), + config); + // Enter in low power mode. + wait_for_interrupt(); +} + +bool test_main(void) { + // Enable global and external IRQ at Ibex. + irq_global_ctrl(true); + irq_external_ctrl(true); + + init_peripherals(); + + // Enable all the AON interrupts used in this test. + rv_plic_testutils_irq_range_enable(&plic, kPlicTarget, + kTopMatchaPlicIrqIdAlertHandlerClassa, + kTopMatchaPlicIrqIdAlertHandlerClassd); + + alert_handler_config(); + + // First check the flash stored value + uint32_t event_idx = flash_ctrl_testutils_counter_get(0); + + // Enable flash access + flash_ctrl_testutils_default_region_access(&flash_ctrl, + /*rd_en*/ true, + /*prog_en*/ true, + /*erase_en*/ true, + /*scramble_en*/ false, + /*ecc_en*/ false, + /*he_en*/ false); + + // Increment flash counter to know where we are + flash_ctrl_testutils_counter_increment(&flash_ctrl, 0); + + LOG_INFO("Test round %d", event_idx); + LOG_INFO("RST_IDX[%d] = %d", event_idx, RST_IDX[event_idx]); + + // Check if there was a HW reset caused by expected cases + dif_rstmgr_reset_info_bitfield_t rst_info; + rst_info = rstmgr_testutils_reason_get(); + rstmgr_testutils_reason_clear(); + LOG_INFO("reset info = %02X", rst_info); + + CHECK(rst_info == kDifRstmgrResetInfoPor || + rst_info == kDifRstmgrResetInfoSysRstCtrl || + rst_info == kDifRstmgrResetInfoWatchdog || + rst_info == kDifRstmgrResetInfoEscalation || + rst_info == kDifRstmgrResetInfoLowPowerExit || + rst_info == (kDifRstmgrResetInfoSysRstCtrl | + kDifRstmgrResetInfoLowPowerExit) || + rst_info == (kDifRstmgrResetInfoPowerUnstable | + kDifRstmgrResetInfoLowPowerExit) || + rst_info == (kDifRstmgrResetInfoPowerUnstable | + kDifRstmgrResetInfoWatchdog | + kDifRstmgrResetInfoLowPowerExit) || + rst_info == (kDifRstmgrResetInfoPowerUnstable | + kDifRstmgrResetInfoWatchdog) || + rst_info == kDifRstmgrResetInfoPowerUnstable || + rst_info == + (kDifRstmgrResetInfoPor | kDifRstmgrResetInfoLowPowerExit) || + rst_info == (kDifRstmgrResetInfoWatchdog | + kDifRstmgrResetInfoLowPowerExit) || + rst_info == (kDifRstmgrResetInfoEscalation | + kDifRstmgrResetInfoLowPowerExit) || + rst_info == kDifRstmgrResetInfoSw, + "Wrong reset reason %02X", rst_info); + + switch (RST_IDX[event_idx] / 2) { + case 0: + if (RST_IDX[event_idx] % 2) { + LOG_INFO("Booting and setting normal sleep followed by glitch reset"); + LOG_INFO("Let SV wait timer reset"); + normal_sleep_glitch_reset(&pwrmgr); + timer_on(kWdogBiteMicros); + } else { + LOG_INFO("Booting and setting deep sleep followed by glitch reset"); + LOG_INFO("Let SV wait timer reset"); + low_power_glitch_reset(&pwrmgr); + } + break; + case 1: + if (RST_IDX[event_idx] % 2) { + LOG_INFO("Booting and setting normal sleep followed by hw por"); + LOG_INFO("Let SV wait timer reset"); + normal_sleep_por(&pwrmgr); + timer_on(kWdogBiteMicros); + } else { + LOG_INFO("Booting and setting deep sleep followed by hw por"); + LOG_INFO("Let SV wait timer reset"); + low_power_por(&pwrmgr); + } + break; + case 2: + if (RST_IDX[event_idx] % 2) { + LOG_INFO( + "Booting and setting normal sleep mode followed for low_power " + "entry reset"); + LOG_INFO("Let SV wait timer reset"); + // actually the same test as normal sleep + watchdog + rstmgr_testutils_pre_reset(&rstmgr); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + normal_sleep_wdog(&pwrmgr); + timer_on(kEscalationPhase0MicrosCpu); + } else { + LOG_INFO( + "Booting and setting deep sleep mode followed for low_power entry " + "reset"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + // actually the same test as deep sleep + watchdog + rstmgr_testutils_pre_reset(&rstmgr); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + low_power_wdog(&pwrmgr); + } + break; + + case 3: + if (RST_IDX[event_idx] % 2) { + LOG_INFO( + "Booting and setting normal sleep followed by watchdog reset " + "combined " + "with sw_req"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + rstmgr_testutils_pre_reset(&rstmgr); + CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr)); + LOG_INFO("Device reset from sw"); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + normal_sleep_wdog(&pwrmgr); + timer_on(kEscalationPhase0MicrosCpu); + } else { + LOG_INFO( + "Booting and setting deep sleep followed by watchdog reset " + "combined " + "with sw_req"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + rstmgr_testutils_pre_reset(&rstmgr); + CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr)); + LOG_INFO("Device reset from sw"); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + low_power_wdog(&pwrmgr); + } + break; + case 4: + if (RST_IDX[event_idx] % 2) { + LOG_INFO("Booting and setting normal sleep followed by watchdog reset"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + rstmgr_testutils_pre_reset(&rstmgr); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + normal_sleep_wdog(&pwrmgr); + timer_on(kEscalationPhase0MicrosCpu); + } else { + LOG_INFO("Booting and setting deep sleep followed by watchdog reset"); + LOG_INFO("Let SV wait timer reset"); + // Executing the wdog bite reset during sleep test. + rstmgr_testutils_pre_reset(&rstmgr); + sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200); + low_power_wdog(&pwrmgr); + } + break; + case 5: + if (RST_IDX[event_idx] % 2) { + LOG_INFO("Last Booting"); + + return true; + } else { + LOG_INFO( + "Booting and running normal sleep followed by escalation reset"); + config_escalate(&aon_timer, &pwrmgr); + timer_on(kEscalationPhase0MicrosCpu); + } + break; + default: + LOG_INFO("Booting for undefined case"); + } + + return false; +}
diff --git a/sw/device/tests/sim_dv/sleep_pin_retention_test.c b/sw/device/tests/sim_dv/sleep_pin_retention_test.c new file mode 100644 index 0000000..750e90e --- /dev/null +++ b/sw/device/tests/sim_dv/sleep_pin_retention_test.c
@@ -0,0 +1,214 @@ +// 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_gpio.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_gpio_t gpio; +static dif_pwrmgr_t pwrmgr; +static dif_pinmux_t pinmux; +static dif_pwrmgr_domain_config_t pwrmgr_domain_cfg; +static dif_rv_plic_t plic; + +static plic_isr_ctx_t plic_ctx = {.rv_plic = &plic, .hart_id = kPlicTarget}; +static pwrmgr_isr_ctx_t pwrmgr_isr_ctx = { + .pwrmgr = &pwrmgr, + .plic_pwrmgr_start_irq_id = kTopMatchaPlicIrqIdPwrmgrAonWakeup, + .expected_irq = kDifPwrmgrIrqWakeup, + .is_only_irq = true}; + +// SV randomizes the round of entering/exiting sleep then set this volatile +// variable via backdoor_overwrite. +static volatile const uint8_t kRounds = 2; + +// SW testcode randomly chooses the value for 8 GPIO pins (pins are fixed) then +// invert the value for retention. SW will sends the value to SV testbench via +// LOG_INFO(). +static const uint8_t kGpioVal = 0x00; + +// To wakeup and maintain GPIO, for now test enters to normal sleep only. +static const bool deepPowerdown = false; + +// Num of GPIO Pads to test +enum { kNumGpioPads = 8 }; + +/** + * 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); + + // Clear PINMUX WKUP_CAUSE reg + CHECK_DIF_OK(dif_pinmux_wakeup_cause_clear(&pinmux)); +} + +/** + * A round of GPIO[7:0] retention value test. + * + * The test sequence is: + * + * 1. Randomly choose GPIO[7:0] value using rand_testutils. + * 2. Drive GPIO with the chosen value. + * 3. Send the chosen values to SV via LOG_INFO. + * 4. Configure PINMUX Retention value opposit to the chosen value for + * GPIO[7:0]. + * 5. Initiate sleep mode (assuming pinmux pin wake up has been configured.) + * 6. WFI() + * 7. At this point, chip has been waken up by DV. Send a log to DV that chip + * has waken up. + * + * DV env checks all PIN value. SW simply drives the GPIO and invert the value + * for retention. + */ +void gpio_test(dif_pwrmgr_t *pwrmgr, dif_pinmux_t *pinmux, dif_gpio_t *gpio, + int round) { + uint8_t gpio_val = 0; + dif_pinmux_pad_kind_t pad_kind; + dif_pinmux_sleep_mode_t pad_mode; + + LOG_INFO("Current Test Round: %1d", round); + + // 1. Randomly choose GPIO value + gpio_val = rand_testutils_gen32_range(0, 255); + + // 2. Drive GPIO with the chosen value. + CHECK_DIF_OK(dif_gpio_write_masked(gpio, (dif_gpio_mask_t)0x000000FF, + (dif_gpio_state_t)gpio_val)); + + // 3. Send the chosen value to SV via LOG_INFO. + // + // The format is: + // + // Chosen GPIO value: %2x + LOG_INFO("Chosen GPIO value: %2x", gpio_val); + + // 4. Configure PINMUX Retention value opposite to the chosen value. + pad_kind = kDifPinmuxPadKindMio; + for (int i = 0; i < kNumGpioPads; i++) { + // GPIO are assigned starting from MIO0 + pad_mode = ((gpio_val >> i) & 0x1) ? kDifPinmuxSleepModeLow + : kDifPinmuxSleepModeHigh; + CHECK_DIF_OK(dif_pinmux_pad_sleep_enable( + pinmux, kTopMatchaPinmuxMioOutIoa0 + i, pad_kind, pad_mode)); + } + + // 5. Initiate sleep mode + pwrmgr_testutils_enable_low_power(pwrmgr, kDifPwrmgrWakeupRequestSourceThree, + pwrmgr_domain_cfg); + // 6. WFI() + LOG_INFO("Entering low power mode."); + wait_for_interrupt(); + + // 7. Turn-off retention. + for (int i = 0; i < kNumGpioPads; i++) { + CHECK_DIF_OK(dif_pinmux_pad_sleep_clear_state( + pinmux, kTopMatchaPinmuxMioOutIoa0 + i, pad_kind)); + } +} + +/** + * Configure GPIO + * + * gpio_init() configures first 8 MIO PADs to GPIO[7:0]. + */ +void gpio_init(const dif_pinmux_t *pinmux, const dif_gpio_t *gpio) { + // Drive GPIO first + CHECK_DIF_OK( + dif_gpio_output_set_enabled_all(gpio, (dif_gpio_state_t)0x000000FFu)); + CHECK_DIF_OK(dif_gpio_write_masked(gpio, (dif_gpio_mask_t)0x000000FF, + (dif_gpio_state_t)0x00000000)); + + // Configure PINMUX to GPIO + for (int i = 0; i < kNumGpioPads; i++) { + CHECK_DIF_OK(dif_pinmux_input_select( + pinmux, kTopMatchaPinmuxPeripheralInGpioGpio0 + i, + kTopMatchaPinmuxInselIoa0 + i)); + CHECK_DIF_OK(dif_pinmux_output_select(pinmux, + kTopMatchaPinmuxMioOutIoa0 + i, + kTopMatchaPinmuxOutselGpioGpio0 + i)); + } +} + +bool test_main(void) { + bool result = true; + + dif_pinmux_index_t detector; + dif_pinmux_wakeup_config_t wakeup_cfg; + + // Default Deep Power Down + + // 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)); + CHECK_DIF_OK( + dif_gpio_init(mmio_region_from_addr(TOP_MATCHA_GPIO_BASE_ADDR), &gpio)); + + // Enable all the AON interrupts used in this test. + rv_plic_testutils_irq_range_enable(&plic, kPlicTarget, + kTopMatchaPlicIrqIdPwrmgrAonWakeup, + kTopMatchaPlicIrqIdPwrmgrAonWakeup); + // Enable pwrmgr interrupt + CHECK_DIF_OK(dif_pwrmgr_irq_set_enabled(&pwrmgr, 0, kDifToggleEnabled)); + + // Wakeup configs + wakeup_cfg.mode = kDifPinmuxWakeupModePositiveEdge; + wakeup_cfg.signal_filter = false; + wakeup_cfg.pad_type = 0; // MIO + wakeup_cfg.pad_select = kTopMatchaPinmuxInselIoa8; // MIO08 + + // Configure Wakeup Detector 0 + CHECK_DIF_OK(dif_pinmux_wakeup_detector_enable(&pinmux, 0, wakeup_cfg)); + + if (deepPowerdown == false) { + // Configure Normal Sleep + pwrmgr_domain_cfg = kDifPwrmgrDomainOptionMainPowerInLowPower | + kDifPwrmgrDomainOptionUsbClockInActivePower; + } + + LOG_INFO("Num Rounds: %3d", kRounds); + + // Select IOA0:IOA7 to GPIO + gpio_init(&pinmux, &gpio); + + // Set wakeup condition. Always use GPIO[8] for Pinmux PIN Wakeup. + + for (int i = kRounds - 1; i >= 0; i--) { + gpio_test(&pwrmgr, &pinmux, &gpio, i); + } + + return result; +}
diff --git a/util/topgen_matcha/templates/chiplevel.sv.tpl b/util/topgen_matcha/templates/chiplevel.sv.tpl index 1c0daf1..87945c3 100644 --- a/util/topgen_matcha/templates/chiplevel.sv.tpl +++ b/util/topgen_matcha/templates/chiplevel.sv.tpl
@@ -697,15 +697,19 @@ .clk_src_usb_o ( ast_base_clks.clk_usb ), .clk_src_usb_val_o ( ast_base_pwr.usb_clk_val ), // smc source clock + .clk_src_smc_en_i ( base_ast_pwr.smc_clk_en ), .clk_src_smc_o ( ast_base_clks.clk_smc ), .clk_src_smc_val_o ( ast_base_pwr.smc_clk_val), // ml source clock + .clk_src_ml_en_i ( base_ast_pwr.ml_clk_en ), .clk_src_ml_o ( ast_base_clks.clk_ml ), .clk_src_ml_val_o ( ast_base_pwr.ml_clk_val), // video source clock + .clk_src_video_en_i ( base_ast_pwr.video_clk_en ), .clk_src_video_o ( ast_base_clks.clk_video ), .clk_src_video_val_o ( ast_base_pwr.video_clk_val), // audio source clock + .clk_src_audio_en_i ( base_ast_pwr.audio_clk_en ), .clk_src_audio_o ( ast_base_clks.clk_audio ), .clk_src_audio_val_o ( ast_base_pwr.audio_clk_val), // adc