blob: 6d04414ecd3b3c2b255f45fdb1ab62fe6e075b6a [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// This sequence will verify the ultra low power feature. It detects the specific
// signal transition on pwrb_in, ac_present and lid_open pins, starts the timer
// configured in registers. Once the timing condition is met, ulp_status and wkup_status
// registers gets updated with the triggered event. Software will read and clear the register.
class sysrst_ctrl_ultra_low_pwr_vseq extends sysrst_ctrl_base_vseq;
`uvm_object_utils(sysrst_ctrl_ultra_low_pwr_vseq)
`uvm_object_new
rand uint16_t set_pwrb_timer, set_lid_timer, set_ac_timer;
rand int pwrb_cycles, ac_cycles, lid_cycles;
rand bit en_ulp;
constraint set_pwrb_timer_c {
set_pwrb_timer dist {
[10:100] :/ 95,
[101:$] :/ 5
};
}
constraint set_lid_timer_c {
set_lid_timer dist {
[10:100] :/ 95,
[101:$] :/ 5
};
}
constraint set_ac_timer_c {
set_ac_timer dist {
[10:100] :/ 95,
[101:$] :/ 5
};
}
constraint pwrb_cycles_c { pwrb_cycles dist {
[1 : set_pwrb_timer] :/20,
(set_pwrb_timer + 1) :/20,
[set_pwrb_timer + 2 : set_pwrb_timer * 2] :/60
};
}
constraint lid_cycles_c { lid_cycles dist {
[1 : set_lid_timer] :/20,
(set_lid_timer + 1) :/20,
[set_lid_timer + 2 : set_lid_timer * 2] :/60
};
}
constraint ac_cycles_c { ac_cycles dist {
[1 : set_ac_timer] :/20,
(set_ac_timer + 1) :/20,
[set_ac_timer + 2 : set_ac_timer * 2] :/60
};
}
constraint num_trans_c {num_trans inside {[1 : 3]};}
task drive_ac();
cfg.vif.ac_present = 1;
cfg.clk_aon_rst_vif.wait_clks(ac_cycles);
cfg.vif.ac_present = 0;
endtask
task drive_pwrb();
cfg.vif.pwrb_in = 1;
cfg.clk_aon_rst_vif.wait_clks($urandom_range(1,20));
cfg.vif.pwrb_in = 0;
cfg.clk_aon_rst_vif.wait_clks(pwrb_cycles);
cfg.vif.pwrb_in = 1;
endtask
task drive_lid();
cfg.vif.lid_open = 0;
cfg.clk_aon_rst_vif.wait_clks($urandom_range(1,20));
cfg.vif.lid_open = 1;
cfg.clk_aon_rst_vif.wait_clks(lid_cycles);
cfg.vif.lid_open = 0;
endtask
task body();
uvm_reg_data_t rdata, wkup_sts_rdata;
uint16_t get_ac_timer, get_pwrb_timer, get_lid_timer;
bit enable_ulp;
`uvm_info(`gfn, "Starting the body from ultra_low_pwr_vseq", UVM_LOW)
repeat (num_trans) begin
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(en_ulp)
// Enable ultra low power feature
ral.ulp_ctl.ulp_enable.set(en_ulp);
csr_update(ral.ulp_ctl);
// Set the debounce timer for pwrb, ac and lid_open
csr_wr(ral.ulp_ac_debounce_ctl, set_ac_timer);
csr_wr(ral.ulp_lid_debounce_ctl, set_lid_timer);
csr_wr(ral.ulp_pwrb_debounce_ctl, set_pwrb_timer);
// Disable the bus clock
cfg.clk_rst_vif.stop_clk();
// It takes 2-3 clock cycles to sync the register values
cfg.clk_aon_rst_vif.wait_clks(2);
repeat ($urandom_range(1,5)) begin
fork
begin
cfg.clk_aon_rst_vif.wait_clks(1);
drive_pwrb();
end
begin
cfg.clk_aon_rst_vif.wait_clks(1);
drive_ac();
end
begin
cfg.clk_aon_rst_vif.wait_clks(1);
drive_lid();
end
join
end
// Enable the bus clock to read the status register
cfg.clk_rst_vif.start_clk();
csr_rd(ral.ulp_ac_debounce_ctl, get_ac_timer);
csr_rd(ral.ulp_pwrb_debounce_ctl, get_pwrb_timer);
csr_rd(ral.ulp_lid_debounce_ctl, get_lid_timer);
csr_rd(ral.ulp_ctl, rdata);
enable_ulp = get_field_val(ral.ulp_ctl.ulp_enable, rdata);
`uvm_info(`gfn, $sformatf("enable_ulp=%0b, pwrb_cycles=%0d, pwrb_timer=%0d, ac_cycles=%0d,\
get_ac_timer=%0d, lid_cycles=%0d, lid_timer=%0d", enable_ulp, pwrb_cycles,
get_pwrb_timer, ac_cycles, get_ac_timer, lid_cycles, get_lid_timer), UVM_MEDIUM)
// (cycles == timer) => sysrst_ctrl_detect.state : DebounceSt -> IdleSt
// (cycles == timer + 1) => sysrst_ctrl_detect.state : DetectSt -> IdleSt
// Therefore we only need to check when cycles > timer + 1
if (enable_ulp == 1 &&
(pwrb_cycles > (get_pwrb_timer + 1) ||
ac_cycles > (get_ac_timer + 1) ||
lid_cycles > (get_lid_timer + 1))) begin
cfg.clk_aon_rst_vif.wait_clks(1);
`DV_CHECK_EQ(cfg.vif.z3_wakeup, 1);
csr_rd(ral.wkup_status, wkup_sts_rdata);
csr_rd_check(ral.wkup_status, .compare_value(1));
// Check if the ulp wakeup event is detected
csr_rd_check(ral.ulp_status, .compare_value(1));
// Clear the ulp_status register
csr_wr(ral.ulp_status, 'h1);
cfg.clk_aon_rst_vif.wait_clks(20);
// Check if the register is cleared
csr_rd_check(ral.ulp_status, .compare_value(0));
// Disable the ultra low power feature
ral.ulp_ctl.ulp_enable.set(0);
csr_update(ral.ulp_ctl);
// Clear the wkup_status register
csr_wr(ral.wkup_status, 'h1);
cfg.clk_aon_rst_vif.wait_clks(20);
// Check if the register is cleared
csr_rd_check(ral.wkup_status, .compare_value(0));
end else begin
`DV_CHECK_EQ(cfg.vif.z3_wakeup, 0);
csr_rd(ral.wkup_status,wkup_sts_rdata);
csr_rd_check(ral.wkup_status, .compare_value(0));
csr_rd_check(ral.ulp_status, .compare_value(0));
end
// Sample the wakeup event covergroup before clearing the status register
if (cfg.en_cov) begin
cov.wakeup_event.sysrst_ctrl_wkup_event_cg.sample(
get_field_val(ral.wkup_status.wakeup_sts, wkup_sts_rdata),
cfg.vif.pwrb_in,
cfg.vif.lid_open,
cfg.vif.ac_present,
cfg.intr_vif.pins
);
end
cfg.clk_aon_rst_vif.wait_clks(10);
end
endtask : body
endclass : sysrst_ctrl_ultra_low_pwr_vseq