[hw,sysrst_ctrl] Add test for combo detect with precondition

1. Add new sequence randomizing all of combo detect configuration registers
   as listed in #17278
2. Move common tasks and functions from combo detect sequences to
   base sequence of sysrst_ctrl
3. Update randomize_combo_input task to prevent randomizing input signals
   that have activated precondition logic
4. Update get_combo_input function to optionally take an input argument,
   specifying the input inversion setting
5. change illegal_bins to ignore_bins as these scenarios are not illegal
6. Add sample function for predetection timer in scoreboard

Signed-off-by: Raviteja Chatta <crteja@lowrisc.org>
diff --git a/hw/ip/sysrst_ctrl/data/sysrst_ctrl_testplan.hjson b/hw/ip/sysrst_ctrl/data/sysrst_ctrl_testplan.hjson
index e43cd46..fe66e88 100644
--- a/hw/ip/sysrst_ctrl/data/sysrst_ctrl_testplan.hjson
+++ b/hw/ip/sysrst_ctrl/data/sysrst_ctrl_testplan.hjson
@@ -87,6 +87,26 @@
     }
 
     {
+      name: combo_detect_with_pre_cond
+      desc: '''
+            Verify the combo detection with random action and precondition.
+
+            * Randomly set the input keys combination as precondition by configuring COM_PRE_SEL_CTL_0-3 register.
+            * Randomly set the input keys combination for combo detection by configuring COM_SEL_CTL_0-3 register.
+            * Set the random combo precondition duration via the COM_PRE_DET_CTL_0-3 register.
+            * Set the random combo duration via the COM_DET_CTL_0-3 register.
+            * Randomly select the action to be taken by configuring COM_OUT_CTL_0-3 register.
+            * Set the pulse width via EC_RST_CTL register.
+            * Randomly set the input keys, such that precondition and subsequent combo detection logic are activated randomly.
+            * Read the COMBO_INTR_STATUS register to check whether an interrupt is correctly raised for all the combinations.
+              Clear the interrupt in case it was raised.
+            * Check for bat_disable, rst_req or wake_up_o assertion depending on COM_OUT_CTL_0-3 register
+            '''
+      stage: V2
+      tests: ["sysrst_ctrl_combo_detect_with_pre_cond"]
+    }
+
+    {
       name: auto_block_key_outputs
       desc: '''
             Verify the auto block key output feature.
diff --git a/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_base_vseq.sv b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_base_vseq.sv
index bb19d4f..e78e877 100644
--- a/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_base_vseq.sv
+++ b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_base_vseq.sv
@@ -20,6 +20,45 @@
     cfg.clk_aon_rst_vif.set_freq_khz(200);
   endtask
 
+  // Set the inputs back to inactive
+  virtual function void reset_combo_inputs(bit[4:0] input_invert=5'h0);
+    cfg.vif.key0_in = ~input_invert[0];
+    cfg.vif.key1_in = ~input_invert[1];
+    cfg.vif.key2_in = ~input_invert[2];
+    cfg.vif.pwrb_in = ~input_invert[3];
+    cfg.vif.ac_present = ~input_invert[4];
+  endfunction
+
+  // Get input of combo detection logic
+  virtual function bit[4:0] get_combo_input();
+    get_combo_input[0] = cfg.vif.key0_in;
+    get_combo_input[1] = cfg.vif.key1_in;
+    get_combo_input[2] = cfg.vif.key2_in;
+    get_combo_input[3] = cfg.vif.pwrb_in;
+    get_combo_input[4] = cfg.vif.ac_present;
+  endfunction
+
+
+  // Disable ec_rst_l_o override
+  virtual task release_ec_rst_l_o();
+    uint16_t get_ec_rst_timer;
+
+    // Explicitly release the EC reset
+    // Disable the override function
+    ral.pin_out_ctl.ec_rst_l.set(0);
+    csr_update(ral.pin_out_ctl);
+    // Get the ec_rst timer value
+    csr_rd(ral.ec_rst_ctl, get_ec_rst_timer);
+
+    // Check ec_rst_l asserts for ec_rst_timer cycles after reset
+    monitor_ec_rst_low(get_ec_rst_timer);
+    cfg.clk_aon_rst_vif.wait_clks(10);
+
+    // ec_rst_l_o remains high
+    `DV_CHECK_EQ(cfg.vif.ec_rst_l_out, 1);
+
+  endtask
+
   virtual task monitor_ec_rst_low(int exp_cycles);
     int act_cycles, wait_cycles;
     int aon_period_ns = cfg.clk_aon_rst_vif.clk_period_ps / 1000;
@@ -31,7 +70,7 @@
     `DV_SPINWAIT(while (cfg.vif.ec_rst_l_out != 1) begin
                    cfg.clk_aon_rst_vif.wait_clks(1);
                    act_cycles++;
-                 end,"time out waiting for ec_rst == 1",aon_period_ns * (exp_cycles + 3))
+                 end, "time out waiting for ec_rst == 1", aon_period_ns * (exp_cycles + 10))
     `DV_CHECK(act_cycles inside {[exp_cycles - 3 : exp_cycles + 3]},
               $sformatf("act(%0d) vs exp(%0d) +/-3", act_cycles, exp_cycles))
   endtask
diff --git a/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_combo_detect_vseq.sv b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_combo_detect_vseq.sv
index 34031a4..e461e13 100644
--- a/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_combo_detect_vseq.sv
+++ b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_combo_detect_vseq.sv
@@ -100,34 +100,6 @@
                                  set_key_timer), UVM_LOW);
   endtask
 
-  function void reset_combo_inputs();
-    // Set the inputs back to inactive to avoid its affect in next iterations
-    cfg.vif.pwrb_in = 1;
-    cfg.vif.key0_in = 1;
-    cfg.vif.key1_in = 1;
-    cfg.vif.key2_in = 1;
-    cfg.vif.ac_present = 1;
-  endfunction
-
-  task release_ec_rst_l_o();
-    uint16_t get_ec_rst_timer;
-
-    // Explicitly release the EC reset
-    // Disable the override function
-    ral.pin_out_ctl.ec_rst_l.set(0);
-    csr_update(ral.pin_out_ctl);
-    // Get the ec_rst timer value
-    csr_rd(ral.ec_rst_ctl, get_ec_rst_timer);
-
-    // Check ec_rst_l asserts for ec_rst_timer cycles after reset
-    monitor_ec_rst_low(get_ec_rst_timer);
-    cfg.clk_aon_rst_vif.wait_clks(10);
-
-    // ec_rst_l_o remains high
-    `DV_CHECK_EQ(cfg.vif.ec_rst_l_out, 1);
-
-  endtask
-
   task body();
     uvm_reg_data_t rdata;
     bit triggered[4];
diff --git a/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_combo_detect_with_pre_cond_vseq.sv b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_combo_detect_with_pre_cond_vseq.sv
new file mode 100644
index 0000000..4025953
--- /dev/null
+++ b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_combo_detect_with_pre_cond_vseq.sv
@@ -0,0 +1,574 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This sequence writes a random values to combo detect registers including
+// precondition settings and checks for the combo detect interrupt.
+class sysrst_ctrl_combo_detect_with_pre_cond_vseq extends sysrst_ctrl_base_vseq;
+  `uvm_object_utils(sysrst_ctrl_combo_detect_with_pre_cond_vseq)
+
+  `uvm_object_new
+  rand uvm_reg_data_t set_action[4];
+  rand bit [4:0] trigger_combo[4], trigger_combo_precondition[4];
+  rand uint16_t set_duration[4], set_duration_precondition[4];
+  rand uint16_t cycles, cycles_precondition;
+  rand uint16_t set_pulse_width, set_key_timer, num_trans_combo_detect;
+  bit ec_rst_h2l_expected = 0 ;
+  bit ec_rst_l2h_expected = 0 ;
+  bit disable_ec_rst_check = 0;
+
+  constraint num_trans_c {num_trans == 50;}
+
+  constraint num_trans_combo_detect_c {num_trans_combo_detect == 10;}
+
+  constraint trigger_combo_precondition_c {
+    foreach (trigger_combo_precondition[i]) {
+      trigger_combo_precondition[i] != 0;
+    }
+  }
+
+  constraint trigger_combo_c {
+     foreach (trigger_combo[i]) {
+       trigger_combo[i] != 0;
+       (trigger_combo[i] & trigger_combo_precondition[i]) == 0;
+     }
+   }
+
+  constraint set_duration_precondition_c {
+    foreach (set_duration_precondition[i]) {
+      set_duration_precondition[i] dist {
+        [10 : 50]  :/ 95,
+        [51 : 300] :/ 5
+      };
+    }
+  }
+
+  constraint set_duration_c {
+    foreach (set_duration[i]) {
+      set_duration[i] dist {
+        [10 : 50 ] :/ 95,
+        [51 : 300] :/ 5
+      };
+    }
+  }
+
+  constraint set_pulse_width_c {
+    set_pulse_width dist {
+      [10 : 50]  :/ 95,
+      [51 : 300] :/ 5
+    };
+    // ec_rst will trigger a pulse, we check all the action after 4 set_duration are done
+    // make the set_pulse_width larger than any of the duration, so that we can still check it's
+    // value.
+    foreach (set_duration[i]) {
+      if (cycles > set_duration[i] + set_key_timer) {
+        set_pulse_width > cycles - (set_duration[i] + set_key_timer);
+      }
+    }
+  }
+
+  constraint set_key_timer_c {
+    set_key_timer dist {
+        [10 : 50 ]  :/ 95,
+        [51 : 300]  :/ 5
+    };
+  }
+
+  constraint cycles_c {
+    foreach (set_duration[i]) {
+      cycles dist {
+        [1 : (set_duration[i] + set_key_timer) - 2] :/ 5,
+        [(set_duration[i] + set_key_timer) + 5 : (set_duration[i] + set_key_timer) * 2] :/ 95
+      };
+    }
+  }
+
+  constraint cycles_precondition_c {
+    foreach (set_duration_precondition[i]) {
+      solve set_duration_precondition[i] before cycles_precondition;
+      cycles_precondition dist {
+        [1 : (set_duration_precondition[i] + set_key_timer) - 2] :/ 5,
+        [(set_duration_precondition[i]) + 5 :
+                     (set_duration_precondition[i] + set_key_timer) * 2]   :/ 95
+      };
+    }
+  }
+
+  task ec_rst_transition_check();
+    `uvm_info(`gfn, "Started ec_rst_l_o transition check", UVM_LOW)
+    fork
+      begin : ec_rst_posedge_check
+        forever begin
+          @(posedge cfg.vif.ec_rst_l_out);
+          wait(cfg.vif.ec_rst_l_out);
+          if(!disable_ec_rst_check)
+            `DV_CHECK(ec_rst_l2h_expected == 1, "Unexpected L2H transition of ec_rst_l_o");
+        end
+      end : ec_rst_posedge_check
+      begin : ec_rst_negedge_check
+        forever begin
+          @(negedge cfg.vif.ec_rst_l_out);
+          wait(!cfg.vif.ec_rst_l_out);
+          if(!disable_ec_rst_check)
+            `DV_CHECK(ec_rst_h2l_expected == 1, "Unexpected H2L transition of ec_rst_l_o");
+        end
+      end : ec_rst_negedge_check
+    join_none
+  endtask
+
+  task automatic set_ec_rst_transition_bits(ref int start_cycles[$], uint16_t pulse_width);
+    int window = 4, pulse_width_l, start_cycle;
+    if( start_cycles.size() == 0) return;
+    start_cycles.sort();
+    start_cycle = start_cycles[0];
+    // Update the aggregate pulse width in case of multiple combo blocks asserting ec_rst_l_o
+    if(start_cycles.size() == 1) begin
+      pulse_width_l = pulse_width;
+    end
+    else begin
+      if((start_cycles[0] + pulse_width) > start_cycles[$]) begin
+        pulse_width_l = pulse_width + (start_cycles[$] - start_cycles[0]);
+      end
+    end
+    `uvm_info(`gfn, $sformatf("pulse_width_l = %0d", pulse_width_l), UVM_LOW)
+
+    fork
+      begin
+        // Wait 2 cycles to account for domain crossing
+        cfg.clk_aon_rst_vif.wait_clks(2);
+        cfg.clk_aon_rst_vif.wait_clks(start_cycle-1);
+        ec_rst_h2l_expected = 1;
+        `uvm_info(`gfn, "ec_rst_h2l_expected == 1", UVM_LOW)
+        cfg.clk_aon_rst_vif.wait_clks(window);
+        ec_rst_h2l_expected = 0;
+        `uvm_info(`gfn, "ec_rst_h2l_expected == 0", UVM_LOW)
+        cfg.clk_aon_rst_vif.wait_clks(pulse_width_l-1);
+        `uvm_info(`gfn, "ec_rst_l2h_expected == 1", UVM_LOW)
+        ec_rst_l2h_expected = 1;
+        cfg.clk_aon_rst_vif.wait_clks(window);
+        ec_rst_l2h_expected = 0;
+        `uvm_info(`gfn, "ec_rst_l2h_expected == 0", UVM_LOW)
+      end
+    join_none
+  endtask
+
+  // Check for a input singal transition that triggers the combo detection logic
+  function bit get_combo_trigger(int index, bit [4:0] combo_input_prev);
+    logic [4:0] in;
+    int count_ones_prev, count_ones;
+    in[0]           = cfg.vif.key0_in;
+    in[1]           = cfg.vif.key1_in;
+    in[2]           = cfg.vif.key2_in;
+    in[3]           = cfg.vif.pwrb_in;
+    in[4]           = cfg.vif.ac_present;
+    count_ones      = $countones(in & trigger_combo[index]);
+    count_ones_prev = $countones(combo_input_prev & trigger_combo[index]);
+    `uvm_info(`gfn, $sformatf(
+              {
+                "DETECTION: i:%0d, in: %5b prev_in: %5b sel:%5b,",
+                "count_ones = %0d count_ones_prev = %0d "
+              },
+              index,
+              in,
+              combo_input_prev,
+              trigger_combo[index],
+              count_ones,
+              count_ones_prev
+              ), UVM_MEDIUM)
+    // Check for Or'd signal transition
+    return ((count_ones_prev > 0) && (count_ones == 0)) && (trigger_combo[index] != 0);
+  endfunction
+
+  // Check for a input combination that triggers the combo precondition logic
+  function bit get_combo_precondition_trigger(int index);
+    logic [4:0] in;
+    in[0] = cfg.vif.key0_in;
+    in[1] = cfg.vif.key1_in;
+    in[2] = cfg.vif.key2_in;
+    in[3] = cfg.vif.pwrb_in;
+    in[4] = cfg.vif.ac_present;
+    `uvm_info(`gfn, $sformatf(
+              "PRECONDITION: i:%0d, in: %5b sel:%5b", index, in, trigger_combo_precondition[index]),
+              UVM_MEDIUM)
+    return ((in & trigger_combo_precondition[index]) == 0);
+  endfunction
+
+  task check_ec_rst_inactive(int max_cycle);
+    cfg.clk_aon_rst_vif.wait_clks($urandom_range(0, max_cycle));
+    `DV_CHECK_EQ(cfg.vif.ec_rst_l_out, 1)
+  endtask
+
+  task config_register();
+    // Select the inputs for precondition
+    foreach (ral.com_pre_sel_ctl[i]) csr_wr(ral.com_pre_sel_ctl[i], trigger_combo_precondition[i]);
+
+    // Set the duration for precondition keys to pressed
+    foreach (ral.com_pre_det_ctl[i]) csr_wr(ral.com_pre_det_ctl[i], set_duration_precondition[i]);
+
+    // Select the inputs for the combo
+    foreach (ral.com_sel_ctl[i]) csr_wr(ral.com_sel_ctl[i], trigger_combo[i]);
+
+    // Set the duration for combo to pressed
+    foreach (ral.com_det_ctl[i]) csr_wr(ral.com_det_ctl[i], set_duration[i]);
+
+    // Set the trigger action
+    foreach (ral.com_out_ctl[i]) csr_wr(ral.com_out_ctl[i], set_action[i]);
+
+    // Set the ec_rst_0 pulse width
+    csr_wr(ral.ec_rst_ctl, set_pulse_width);
+    `uvm_info(`gfn, $sformatf("Write data of ec_rst_ctl register:0x%0h", set_pulse_width), UVM_LOW);
+    // Set the key triggered debounce timer
+    csr_wr(ral.key_intr_debounce_ctl, set_key_timer);
+    `uvm_info(`gfn, $sformatf("Write data of key_intr_debounce_ctl register:0x%0h", set_key_timer),
+              UVM_LOW);
+  endtask
+
+  task monitor_bat_disable_L2H(int exp_cycles);
+    int inactive_cycles = 0;
+    int aon_period_ns = cfg.clk_aon_rst_vif.clk_period_ps / 1000;
+    // Check bat_disable is low for exp_cycles. After exp_cycles+20, below will time out and fail.
+    `DV_SPINWAIT(while (cfg.vif.bat_disable != 1) begin
+                   cfg.clk_aon_rst_vif.wait_clks(1);
+                   inactive_cycles++;
+                 end, "time out waiting for bat_disable == 1",
+                 aon_period_ns * (exp_cycles + 20))
+    `DV_CHECK(inactive_cycles inside {[exp_cycles - 4 : exp_cycles + 4]},
+           $sformatf("bat_disable_check: inact(%0d) vs exp(%0d) +/-4", inactive_cycles, exp_cycles))
+  endtask
+
+  task monitor_rst_req_L2H(int exp_cycles);
+    int inactive_cycles = 0;
+    int aon_period_ns = cfg.clk_aon_rst_vif.clk_period_ps / 1000;
+    // Check rst_req is low for exp_cycles. After exp_cycles+20, below will time out and fail.
+    `DV_SPINWAIT(while (cfg.vif.rst_req != 1) begin
+                   cfg.clk_aon_rst_vif.wait_clks(1);
+                   inactive_cycles++;
+                 end, "time out waiting for rst_req == 1",
+                 aon_period_ns * (exp_cycles + 20))
+    `DV_CHECK(inactive_cycles inside {[exp_cycles - 4 : exp_cycles + 4]},
+            $sformatf("rst_req_check: inact(%0d) vs exp(%0d) +/-4", inactive_cycles, exp_cycles))
+  endtask
+
+  // Sample covergroups with key selections and combo actions
+  function void sample_coverpoints( int i,
+    bit [4:0] trigger_combo_pre,
+    bit [4:0] trigger_combo,
+    bit com_out_intr,
+    bit com_out_bat_disable,
+    bit com_out_ec_rst,
+    bit com_out_rst_req);
+
+    // Sample aggregate key selection
+    bit key0_in_sel_detect = get_field_val( ral.com_sel_ctl[i].key0_in_sel, trigger_combo);
+    bit key1_in_sel_detect = get_field_val( ral.com_sel_ctl[i].key1_in_sel, trigger_combo);
+    bit key2_in_sel_detect = get_field_val( ral.com_sel_ctl[i].key2_in_sel, trigger_combo);
+    bit pwrb_in_sel_detect = get_field_val( ral.com_sel_ctl[i].pwrb_in_sel, trigger_combo);
+    bit ac_present_sel_detect = get_field_val( ral.com_sel_ctl[i].ac_present_sel, trigger_combo);
+    bit key0_in_sel_precond = get_field_val( ral.com_pre_sel_ctl[i].key0_in_sel, trigger_combo_pre);
+    bit key1_in_sel_precond = get_field_val( ral.com_pre_sel_ctl[i].key1_in_sel, trigger_combo_pre);
+    bit key2_in_sel_precond = get_field_val( ral.com_pre_sel_ctl[i].key2_in_sel, trigger_combo_pre);
+    bit pwrb_in_sel_precond = get_field_val( ral.com_pre_sel_ctl[i].pwrb_in_sel, trigger_combo_pre);
+    bit ac_present_sel_precond = get_field_val( ral.com_pre_sel_ctl[i].ac_present_sel,
+                                            trigger_combo_pre);
+    // Sample combo actions and key selections for each combo channel
+    cov.combo_detect_action[i].sysrst_ctrl_combo_detect_action_cg.sample(
+      com_out_bat_disable, com_out_intr, com_out_ec_rst, com_out_rst_req,
+      key0_in_sel_detect,
+      key1_in_sel_detect,
+      key2_in_sel_detect,
+      pwrb_in_sel_detect,
+      ac_present_sel_detect,
+      key0_in_sel_precond,
+      key1_in_sel_precond,
+      key2_in_sel_precond,
+      pwrb_in_sel_precond,
+      ac_present_sel_precond);
+    // Sample key combination coverpoints
+    cov.combo_key_combinations.sysrst_ctrl_combo_key_combinations_cg.sample(
+      .bat_disable    ( com_out_bat_disable ),
+      .interrupt      ( com_out_intr ),
+      .ec_rst         ( com_out_rst_req ),
+      .rst_req        ( com_out_rst_req ),
+      .key0_in_sel    ( key0_in_sel_detect ),
+      .key1_in_sel    ( key1_in_sel_detect ),
+      .key2_in_sel    ( key2_in_sel_detect ),
+      .pwrb_in_sel    ( pwrb_in_sel_detect ),
+      .ac_present_sel ( ac_present_sel_detect ),
+      .precondition_key0_in_sel ( key0_in_sel_precond ),
+      .precondition_key1_in_sel ( key1_in_sel_precond ),
+      .precondition_key2_in_sel ( key2_in_sel_precond ),
+      .precondition_pwrb_in_sel ( pwrb_in_sel_precond ),
+      .precondition_ac_present_sel ( ac_present_sel_precond) );
+  endfunction
+
+  task body();
+
+    `uvm_info(`gfn, "Starting the body from combo detect with precondition", UVM_LOW)
+
+    // Start sequence by releaseing ec_rst_l_o. post reset ec_rst_l_o remains asserted,
+    // and must be deasserted. This is to make sure during test, the H->L and L->H transitions
+    // of ec_rst_l_o can be observed
+    release_ec_rst_l_o();
+    // Reset combo logic input
+    reset_combo_inputs();
+    // Configure combo logic registers
+    config_register();
+
+    `uvm_info(`gfn, $sformatf("Value of cycles_precondition:%0d", cycles_precondition), UVM_LOW)
+    `uvm_info(`gfn, $sformatf("Value of cycles:%0d", cycles), UVM_LOW)
+    // It takes 2-3 clock cycles to sync the register values
+    cfg.clk_aon_rst_vif.wait_clks(3);
+    ec_rst_transition_check();
+    repeat (num_trans) begin : main_block
+      bit precond_detected_for_one_block = 1'b0;
+      bit [3:0] precondition_detected = '{4{1'b0}};
+      // Randomize input
+      repeat ($urandom_range(1, 3)) cfg.vif.randomize_combo_input();
+      // Wait for debounce + detect timer
+      cfg.clk_aon_rst_vif.wait_clks(cycles_precondition);
+      for (int i = 0; i < 4; i++) begin
+        if(cycles_precondition > (set_duration_precondition[i] + set_key_timer) &&
+              get_combo_precondition_trigger(i)) begin
+          precondition_detected[i] = (trigger_combo[i] & trigger_combo_precondition[i]) == 0;
+          precond_detected_for_one_block |= precondition_detected[i];
+        end
+      end
+
+      if (precond_detected_for_one_block) begin : combo_detect_block
+        uvm_reg_data_t  rdata;
+        uint16_t       [3:0] get_duration;
+        uvm_reg_data_t [3:0] get_action;
+        bit [3:0]  combo_detected;
+        bit [4:0]  combo_precondition_mask = 5'd0;
+        bit [4:0]  get_trigger_combo[4];
+        bit [4:0]  get_trigger_combo_pre[4];
+        bit [4:0]  combo_input_prev;
+        bit        combo_triggered[4] = '{1'b0, 1'b0, 1'b0, 1'b0};
+        // Update combo_precondition_mask
+        for (int i = 0; i < 4; i++) begin
+          if (precondition_detected[i]) begin
+            // Dont change the signals asserted for precondition
+            combo_precondition_mask |= trigger_combo_precondition[i];
+            `uvm_info(`gfn, $sformatf("valid precondition detected for combo channel: %0d", i),
+                      UVM_LOW)
+          end
+          else begin
+            // Disable blocks in Idle state
+            csr_wr(ral.com_sel_ctl[i], 5'd0);
+            csr_wr(ral.com_pre_sel_ctl[i], 5'd0);
+          end
+        end
+        // Wait for register updates to take effect
+        cfg.clk_aon_rst_vif.wait_clks(3);
+
+        combo_precondition_mask = ~combo_precondition_mask;
+        `uvm_info(`gfn, $sformatf("precondition_detected= %0x", precondition_detected), UVM_MEDIUM)
+        `uvm_info(`gfn, $sformatf("combo_precondition_mask= %0x", combo_precondition_mask),UVM_LOW)
+
+        while (precondition_detected > 0 && (combo_detected != precondition_detected) &&
+               num_trans_combo_detect>0)  begin : combo_action_check
+          bit bat_act_triggered, ec_act_triggered, rst_act_triggered;
+          bit [3:0] intr_actions, intr_actions_pre_reset;
+          int bat_act_occur_cyc = 0;
+          int rst_req_act_occur_cyc = 0;
+          int bat_act_occur_cycles[$];
+          int rst_req_act_occur_cycles[$];
+          int ec_rst_start_time[$];
+          int max_wait_till_next_iter = set_pulse_width;
+
+          // Sample combo key inputs
+          combo_input_prev = get_combo_input();
+
+          // Sample the combo_intr_status covergroup to capture the trigger combo inputs
+          // before randomizing the inputs
+          if (cfg.en_cov) begin
+            foreach (intr_actions_pre_reset[i]) begin
+              intr_actions_pre_reset[i] =
+                  get_field_val(ral.com_out_ctl[i].interrupt, get_action[i]);
+            end
+            cov.combo_intr_status.sysrst_ctrl_combo_intr_status_cg.sample(
+              get_field_val(ral.combo_intr_status.combo0_h2l, rdata),
+              get_field_val(ral.combo_intr_status.combo1_h2l, rdata),
+              get_field_val(ral.combo_intr_status.combo2_h2l, rdata),
+              get_field_val(ral.combo_intr_status.combo3_h2l, rdata),
+              cfg.vif.key0_in,
+              cfg.vif.key1_in,
+              cfg.vif.key2_in,
+              cfg.vif.pwrb_in,
+              cfg.vif.ac_present,
+              intr_actions_pre_reset);
+          end
+
+          // Read combo detection registers
+          foreach (ral.com_det_ctl[i]) csr_rd(ral.com_det_ctl[i], get_duration[i]);
+          foreach (ral.com_out_ctl[i]) csr_rd(ral.com_out_ctl[i], get_action[i]);
+          foreach (ral.com_sel_ctl[i]) csr_rd(ral.com_sel_ctl[i], get_trigger_combo[i]);
+          foreach (ral.com_sel_ctl[i]) csr_rd(ral.com_pre_sel_ctl[i], get_trigger_combo_pre[i]);
+
+          // Randomize combo logic inputs except the ones asserted for precondition
+          repeat ($urandom_range(1, 3)) cfg.vif.randomize_combo_input(combo_precondition_mask);
+
+          cfg.clk_aon_rst_vif.wait_clks(1);
+          // Update trigger value of Combo channel and ec_rst timing check bits
+          foreach (combo_triggered[i]) begin
+            bit com_out_ec_rst = get_field_val(ral.com_out_ctl[i].ec_rst, get_action[i]);
+            if (precondition_detected[i]) begin
+              int key_detect_time = int'(get_duration[i] + set_key_timer);
+              combo_triggered[i] = get_combo_trigger(i, combo_input_prev);
+              if (com_out_ec_rst && combo_triggered[i] &&
+                  (cycles+set_pulse_width > key_detect_time)) begin
+                ec_rst_start_time.push_back(key_detect_time-1);
+              end
+            end
+          end
+          set_ec_rst_transition_bits(ec_rst_start_time, set_pulse_width);
+          // Wait for debounce + detect timer
+          cfg.clk_aon_rst_vif.wait_clks(cycles-1);
+
+          // Check if the interrupt has raised.
+          // NOTE: The interrupt will only raise if the interrupt combo action is set.
+          for (int i = 0; i < 4; i++) begin
+            if ((cycles + set_pulse_width) > (get_duration[i] + set_key_timer) &&
+               combo_triggered[i])
+            begin
+              int key_detect_time = get_duration[i] + set_key_timer;
+              bit com_out_intr = get_field_val(ral.com_out_ctl[i].interrupt, get_action[i]);
+              bit com_out_bat_disable = get_field_val(ral.com_out_ctl[i].bat_disable,
+                                          get_action[i]);
+              bit com_out_ec_rst = get_field_val(ral.com_out_ctl[i].ec_rst, get_action[i]);
+              bit com_out_rst_req = get_field_val(ral.com_out_ctl[i].rst_req, get_action[i]);
+
+              `uvm_info(`gfn, $sformatf("valid combo input transition detected for channel :%0d",i),
+                                         UVM_LOW)
+              intr_actions[i]    = com_out_intr;
+              bat_act_triggered |= com_out_bat_disable;
+              ec_act_triggered  |= com_out_ec_rst;
+              rst_act_triggered |= com_out_rst_req;
+              if (cfg.en_cov) begin
+                for (int i = 0; i < 4; i++) begin
+                  sample_coverpoints( i,
+                    get_trigger_combo_pre[i],
+                    get_trigger_combo[i],
+                    com_out_intr,
+                    com_out_bat_disable,
+                    com_out_ec_rst,
+                    com_out_rst_req);
+                end
+              end
+              if (com_out_bat_disable) begin
+                bat_act_occur_cycles.push_back(key_detect_time);
+              end
+              if (com_out_rst_req) begin
+                rst_req_act_occur_cycles.push_back(key_detect_time);
+              end
+              combo_detected[i]= com_out_ec_rst | com_out_bat_disable | com_out_intr |
+                                 com_out_rst_req;
+            end
+            `uvm_info(`gfn, $sformatf("bat_act_triggered = %0b", bat_act_triggered), UVM_MEDIUM)
+            `uvm_info(`gfn, $sformatf("rst_act_triggered = %0b", rst_act_triggered), UVM_MEDIUM)
+          end
+          // Update start cycle of output assertion
+          if( bat_act_occur_cycles.size() > 0 ) begin
+            bat_act_occur_cycles.sort();
+            if( bat_act_occur_cycles[0] > cycles)
+              bat_act_occur_cyc = bat_act_occur_cycles[0] - cycles;
+          end
+          if( rst_req_act_occur_cycles.size() > 0 ) begin
+            rst_req_act_occur_cycles.sort();
+            if( rst_req_act_occur_cycles[0] > cycles)
+              rst_req_act_occur_cyc = rst_req_act_occur_cycles[0] - cycles;
+          end
+          `uvm_info(`gfn, $sformatf("bat_act_occur_cyc = %0d", bat_act_occur_cyc), UVM_MEDIUM)
+          `uvm_info(`gfn, $sformatf("rst_req_act_occur_cyc = %0d", rst_req_act_occur_cyc),
+                                     UVM_MEDIUM)
+          // Check for Combo output assertions
+          fork
+            begin
+              // Wait till next iteration
+              cfg.clk_aon_rst_vif.wait_clks(set_pulse_width);
+              // Reset combo inputs except the ones required to enable precondition
+              reset_combo_inputs(~combo_precondition_mask);
+            end
+            begin : bat_disable_check
+              if (bat_act_triggered) begin
+                if (bat_act_occur_cyc > 0) monitor_bat_disable_L2H(bat_act_occur_cyc);
+                else `DV_CHECK_EQ(cfg.vif.bat_disable, 1);
+              end else begin
+                `DV_CHECK_EQ(cfg.vif.bat_disable, 0);
+              end
+            end : bat_disable_check
+            begin : rst_req_check
+              if (rst_act_triggered) begin
+                if (rst_req_act_occur_cyc > 0) monitor_rst_req_L2H(rst_req_act_occur_cyc);
+                else `DV_CHECK_EQ(cfg.vif.rst_req, 1);
+              end else begin
+                `DV_CHECK_EQ(cfg.vif.rst_req, 0);
+              end
+            end : rst_req_check
+          join
+
+          // Check for interrupt status after output check
+          begin : intr_check
+            cfg.clk_aon_rst_vif.wait_clks(1);
+            csr_rd(ral.combo_intr_status, rdata);
+            `DV_CHECK_EQ(rdata, intr_actions)
+            if (intr_actions) begin
+              check_interrupts(.interrupts(1 << IntrSysrstCtrl), .check_set(1));
+
+              // Write to clear the interrupt.
+              csr_wr(ral.combo_intr_status, rdata);
+
+              cfg.clk_aon_rst_vif.wait_clks(5);
+              // Check if the interrupt is cleared.
+              csr_rd_check(ral.combo_intr_status, .compare_value(0));
+              // Sample the combo intr status covergroup.
+              // The combo_intr_status get updated only when the interrupt action is triggered.
+              if (cfg.en_cov) begin
+                cov.combo_intr_status.sysrst_ctrl_combo_intr_status_cg.sample(
+                    get_field_val(ral.combo_intr_status.combo0_h2l, rdata), get_field_val(
+                    ral.combo_intr_status.combo1_h2l, rdata), get_field_val(
+                    ral.combo_intr_status.combo2_h2l, rdata), get_field_val(
+                    ral.combo_intr_status.combo3_h2l, rdata), cfg.vif.key0_in, cfg.vif.key1_in,
+                    cfg.vif.key2_in, cfg.vif.pwrb_in, cfg.vif.ac_present, intr_actions);
+              end
+            end else begin
+              check_interrupts(.interrupts(1 << IntrSysrstCtrl), .check_set(0));
+            end
+          end : intr_check
+
+          // Reset design for sticky combo output settings
+          if (bat_act_triggered || rst_act_triggered) begin
+            disable_ec_rst_check = 1;
+            // Reset combo logic input
+            reset_combo_inputs();
+            apply_resets_concurrently();
+            // Delay to avoid race condition when sending item and checking no item after
+            // reset occur at the same time.
+            #1ps;
+            // Release ec_rst_l_o after reset
+            release_ec_rst_l_o();
+            // Apply_resets_concurrently will set the registers to their default values,
+            // wait for sometime and reconfigure the registers for next iteration.
+            config_register();
+            disable_ec_rst_check = 0;
+            // Reset internal variables
+            precondition_detected = '{4{1'b0}};
+            combo_detected = '{4{1'b0}};
+            // Exit combo_action_check block
+            break;
+          end
+          num_trans_combo_detect--;
+        end : combo_action_check
+      end : combo_detect_block
+      // Reset combo inputs after iteration
+      reset_combo_inputs();
+      // Reprogram the combo selection registers
+      for (int i = 0; i < 4; i++) begin
+        csr_wr(ral.com_sel_ctl[i], trigger_combo[i]);
+        csr_wr(ral.com_pre_sel_ctl[i], trigger_combo_precondition[i]);
+      end
+      cfg.clk_aon_rst_vif.wait_clks(3);
+    end : main_block
+  endtask : body
+
+endclass : sysrst_ctrl_combo_detect_with_pre_cond_vseq
diff --git a/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_vseq_list.sv b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_vseq_list.sv
index 12efdf6..c8ee82d 100644
--- a/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_vseq_list.sv
+++ b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_vseq_list.sv
@@ -17,3 +17,4 @@
 `include "sysrst_ctrl_combo_detect_vseq.sv"
 `include "sysrst_ctrl_edge_detect_vseq.sv"
 `include "sysrst_ctrl_stress_all_vseq.sv"
+`include "sysrst_ctrl_combo_detect_with_pre_cond_vseq.sv"
diff --git a/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_env.core b/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_env.core
index 24fd0b2..234d676 100644
--- a/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_env.core
+++ b/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_env.core
@@ -33,6 +33,7 @@
       - seq_lib/sysrst_ctrl_combo_detect_vseq.sv: {is_include_file: true}
       - seq_lib/sysrst_ctrl_edge_detect_vseq.sv: {is_include_file: true}
       - seq_lib/sysrst_ctrl_stress_all_vseq.sv: {is_include_file: true}
+      - seq_lib/sysrst_ctrl_combo_detect_with_pre_cond_vseq.sv: {is_include_file: true}
     file_type: systemVerilogSource
 
 generate:
diff --git a/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_if.sv b/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_if.sv
index e0aff58..d08096e 100644
--- a/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_if.sv
+++ b/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_if.sv
@@ -57,17 +57,17 @@
     flash_wp_l_in = flash_wp;
   endtask
 
-  task automatic randomize_combo_input();
+  task automatic randomize_combo_input(bit[4:0] mask=5'h1F);
     // VCS doesn't support randomizing logic variable
     // so declare bit variable, randomize it and assigned it to logic
     bit pwrb, key0, key1, key2, ac_prst;
     `DV_CHECK_FATAL(std::randomize(pwrb, key0, key1, key2, ac_prst), ,
        "sysrst_ctrl_if")
-    pwrb_in = pwrb;
-    key0_in = key0;
-    key1_in = key1;
-    key2_in = key2;
-    ac_present = ac_prst;
+    if(mask[0]) key0_in = key0;
+    if(mask[1]) key1_in = key1;
+    if(mask[2]) key2_in = key2;
+    if(mask[3]) pwrb_in = pwrb;
+    if(mask[4]) ac_present = ac_prst;
   endtask
 
   assign sysrst_ctrl_inputs = {flash_wp_l_in, ec_rst_l_in, ac_present, key2_in, key1_in, key0_in,
diff --git a/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_scoreboard.sv b/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_scoreboard.sv
index ca1ad5e..929b726 100644
--- a/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_scoreboard.sv
+++ b/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_scoreboard.sv
@@ -233,9 +233,18 @@
       end
       "alert_test": begin
       end
-      // TODO: need support pre-condition
-      "com_pre_sel_ctl_0", "com_pre_sel_ctl_1", "com_pre_sel_ctl_2", "com_pre_sel_ctl_3",
+      "com_pre_sel_ctl_0", "com_pre_sel_ctl_1", "com_pre_sel_ctl_2", "com_pre_sel_ctl_3": begin
+        // covered in sequence
+      end
       "com_pre_det_ctl_0", "com_pre_det_ctl_1", "com_pre_det_ctl_2", "com_pre_det_ctl_3": begin
+         if (addr_phase_write) begin
+           string csr_name = csr.get_name();
+           string str_idx = csr_name.getc(csr_name.len - 1);
+           int idx = str_idx.atoi();
+           cov_if.cg_combo_precondition_det_sample (idx,
+             get_field_val(ral.com_pre_det_ctl[idx].precondition_timer, item.a_data)
+           );
+         end
       end
       default: begin
        `uvm_error(`gfn, $sformatf("invalid csr: %0s", csr.get_full_name()))
diff --git a/hw/ip/sysrst_ctrl/dv/sysrst_ctrl_sim_cfg.hjson b/hw/ip/sysrst_ctrl/dv/sysrst_ctrl_sim_cfg.hjson
index 49780bc..58a55c3 100644
--- a/hw/ip/sysrst_ctrl/dv/sysrst_ctrl_sim_cfg.hjson
+++ b/hw/ip/sysrst_ctrl/dv/sysrst_ctrl_sim_cfg.hjson
@@ -106,6 +106,11 @@
       uvm_test_seq: sysrst_ctrl_edge_detect_vseq
       run_opts: ["+test_timeout_ns=10_000_000_000"]
     }
+    {
+      name: sysrst_ctrl_combo_detect_with_pre_cond
+      uvm_test_seq: sysrst_ctrl_combo_detect_with_pre_cond_vseq
+      reseed: 100
+    }
   ]
 
   // List of regressions.