[rbox] Added the design files

Signed-off-by: Eric Shiu <eshiu@google.com>
diff --git a/hw/ip/rbox/rtl/rbox.sv b/hw/ip/rbox/rtl/rbox.sv
index cada269..d0ab6f8 100644
--- a/hw/ip/rbox/rtl/rbox.sv
+++ b/hw/ip/rbox/rtl/rbox.sv
@@ -45,8 +45,10 @@
   rbox_hw2reg_t hw2reg;
 
   logic pwrb_int, key0_int, key1_int, key2_int, ac_present_int;
-  logic pwrb_out_hw, key0_out_hw, key1_out_hw, key2_out_hw, ec_rst_l_hw;
+  logic pwrb_out_hw, key0_out_hw, key1_out_hw, key2_out_hw, ec_rst_l_hw, bat_disable_hw;
   logic pwrb_out_int, key0_out_int, key1_out_int, key2_out_int, bat_disable_int;
+  logic rbox_combo_intr, rbox_key_intr;
+  logic nc_intg_err_o;//FIXME
 
   //Always-on pins
   assign cio_ec_rst_l_en_o = 1'b1;
@@ -64,6 +66,7 @@
     .tl_o(tl_o),
     .reg2hw(reg2hw),
     .hw2reg(hw2reg),
+    .intg_err_o(nc_intg_err_o),
     .devmode_i  (1'b1)
   );
 
@@ -77,6 +80,8 @@
     .key0_int(key0_int),
     .key1_int(key1_int),
     .key2_int(key2_int),
+    .auto_block_debounce_ctl_i(reg2hw.auto_block_debounce_ctl),
+    .auto_block_out_ctl_i(reg2hw.auto_block_out_ctl),
     .pwrb_out_hw(pwrb_out_hw),
     .key0_out_hw(key0_out_hw),
     .key1_out_hw(key1_out_hw),
@@ -97,6 +102,7 @@
     .key1_out_int(key1_out_int),
     .key2_out_int(key2_out_int),
     .bat_disable_int(bat_disable_int),
+    .key_invert_ctl_i(reg2hw.key_invert_ctl),
     .pwrb_int(pwrb_int),
     .key0_int(key0_int),
     .key1_int(key1_int),
@@ -127,6 +133,10 @@
     .key2_out_hw(key2_out_hw),
     .bat_disable_hw(bat_disable_hw),
     .ec_rst_l_hw(ec_rst_l_hw),
+    .pin_allowed_ctl_i(reg2hw.pin_allowed_ctl),
+    .pin_out_ctl_i(reg2hw.pin_out_ctl),
+    .pin_out_value_i(reg2hw.pin_out_value),
+    .pin_in_value_o(hw2reg.pin_in_value),
     .pwrb_out_int(pwrb_out_int),
     .key0_out_int(key0_out_int),
     .key1_out_int(key1_out_int),
@@ -146,7 +156,11 @@
     .key1_int(key1_int),
     .key2_int(key2_int),
     .ac_present_int(ac_present_int),
-    .cio_ec_rst_l_i(cio_ec_rst_l_i)
+    .cio_ec_rst_l_i(cio_ec_rst_l_i),
+    .key_intr_ctl_i(reg2hw.key_intr_ctl),
+    .key_intr_debounce_ctl_i(reg2hw.key_intr_debounce_ctl),
+    .key_intr_status_o(hw2reg.key_intr_status),
+    .rbox_key_intr(rbox_key_intr)
   );
 
   //Instantiate combo module
@@ -155,12 +169,19 @@
     .rst_ni(rst_ni),
     .clk_aon_i(clk_aon_i),
     .rst_slow_ni(rst_slow_ni),
-    .pwrb_int(pwr_int),
+    .pwrb_int(pwrb_int),
     .key0_int(key0_int),
     .key1_int(key1_int),
     .key2_int(key2_int),
     .ac_present_int(ac_present_int),
     .cio_ec_rst_l_i(cio_ec_rst_l_i),
+    .ec_rst_ctl_i(reg2hw.ec_rst_ctl),
+    .key_intr_debounce_ctl_i(reg2hw.key_intr_debounce_ctl),
+    .com_sel_ctl_i(reg2hw.com_sel_ctl),
+    .com_det_ctl_i(reg2hw.com_det_ctl),
+    .com_out_ctl_i(reg2hw.com_out_ctl),
+    .combo_intr_status_o(hw2reg.combo_intr_status),
+    .rbox_combo_intr(rbox_combo_intr),
     .bat_disable_hw(bat_disable_hw),
     .gsc_rst_o(gsc_rst_o),
     .ec_rst_l_hw(ec_rst_l_hw)
@@ -170,8 +191,25 @@
   rbox_intr i_intr (
     .clk_i(clk_i),
     .rst_ni(rst_ni),
+    .rbox_combo_intr(rbox_combo_intr),
+    .rbox_key_intr(rbox_key_intr),
+    .intr_state_i(reg2hw.intr_state),
+    .intr_enable_i(reg2hw.intr_enable),
+    .intr_test_i(reg2hw.intr_test),
+    .intr_state_o(hw2reg.intr_state),
     .rbox_intr_o(rbox_intr_o)
   );
 
+  // All outputs should be known value after reset
+  `ASSERT_KNOWN(IntrRboxOKnown, rbox_intr_o)
+  `ASSERT_KNOWN(GSCRstOKnown, gsc_rst_l_o)
+  `ASSERT_KNOWN(TlODValidKnown, tl_o.d_valid)
+  `ASSERT_KNOWN(TlOAReadyKnown, tl_o.a_ready)
+  `ASSERT_KNOWN(BatOKnown, cio_bat_disable_o)
+  `ASSERT_KNOWN(ECRSTOKnown, cio_ec_rst_l_o)
+  `ASSERT_KNOWN(PwrbOKnown, cio_pwrb_out_o)
+  `ASSERT_KNOWN(Key0OKnown, cio_key0_out_o)
+  `ASSERT_KNOWN(Key1OKnown, cio_key1_out_o)
+  `ASSERT_KNOWN(Key2OKnown, cio_key2_out_o)
 
 endmodule
diff --git a/hw/ip/rbox/rtl/rbox_autoblock.sv b/hw/ip/rbox/rtl/rbox_autoblock.sv
new file mode 100644
index 0000000..87f94c3
--- /dev/null
+++ b/hw/ip/rbox/rtl/rbox_autoblock.sv
@@ -0,0 +1,166 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description RBOX PWRB autoblock module
+
+module rbox_autoblock import rbox_reg_pkg::*; (
+  input  clk_aon_i,
+  input  rst_slow_ni,
+  input  clk_i,
+  input  rst_ni,
+
+  input  pwrb_int,
+  input  key0_int,
+  input  key1_int,
+  input  key2_int,
+
+  input  rbox_reg2hw_auto_block_debounce_ctl_reg_t auto_block_debounce_ctl_i,
+  input  rbox_reg2hw_auto_block_out_ctl_reg_t      auto_block_out_ctl_i,
+
+  output pwrb_out_hw,
+  output key0_out_hw,
+  output key1_out_hw,
+  output key2_out_hw
+
+);
+
+  logic         cfg_auto_block_en;
+  logic         load_auto_block_timer;
+  logic [15:0]  cfg_auto_block_timer;
+  logic [15:0]  cfg_auto_block_timer_d;
+  logic         cfg_key0_o_sel;
+  logic         cfg_key1_o_sel;
+  logic         cfg_key2_o_sel;
+  logic         cfg_key0_o_q;
+  logic         cfg_key1_o_q;
+  logic         cfg_key2_o_q;
+
+  logic ab_cond_met;
+  logic pwrb_int_i;
+
+  //nc_ means no connect
+  logic nc_auto_block_enable;
+
+  //synchronize between cfg(24MHz) and always-on(200KHz)
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_auto_block_en (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(auto_block_debounce_ctl_i.auto_block_enable.q),
+    .q_o(cfg_auto_block_en)
+  );
+
+  assign nc_auto_block_enable = auto_block_debounce_ctl_i.auto_block_enable.qe;
+
+  prim_fifo_async #(
+    .Width(16),
+    .Depth(2)
+  ) i_cfg_auto_block_timer (
+    .clk_wr_i  (clk_i),
+    .rst_wr_ni (rst_ni),
+    .wvalid_i  (auto_block_debounce_ctl_i.debounce_timer.qe),
+    .wready_o  (),
+    .wdata_i   (auto_block_debounce_ctl_i.debounce_timer.q),
+    .wdepth_o  (),
+
+    .clk_rd_i  (clk_aon_i),
+    .rst_rd_ni (rst_slow_ni),
+    .rvalid_o  (load_auto_block_timer),
+    .rready_i  (1'b1),
+    .rdata_o   (cfg_auto_block_timer_d),
+    .rdepth_o  ()
+  );
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_cfg_auto_block_timer_reg
+    if (!rst_slow_ni) begin
+      cfg_auto_block_timer    <= '0;
+    end else if (load_auto_block_timer) begin
+      cfg_auto_block_timer    <= cfg_auto_block_timer_d;
+    end
+  end
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key0_o_sel (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(auto_block_out_ctl_i.key0_out_sel.q),
+    .q_o(cfg_key0_o_sel)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key1_o_sel (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(auto_block_out_ctl_i.key1_out_sel.q),
+    .q_o(cfg_key1_o_sel)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key2_o_sel (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(auto_block_out_ctl_i.key2_out_sel.q),
+    .q_o(cfg_key2_o_sel)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key0_o_q (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(auto_block_out_ctl_i.key0_out_value.q),
+    .q_o(cfg_key0_o_q)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key1_o_q (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(auto_block_out_ctl_i.key1_out_value.q),
+    .q_o(cfg_key1_o_q)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key2_o_q (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(auto_block_out_ctl_i.key2_out_value.q),
+    .q_o(cfg_key2_o_q)
+  );
+
+  //synchronize between GPIO and always-on(200KHz)
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_pwrb_in_i (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pwrb_int),
+    .q_o(pwrb_int_i)
+  );
+
+  rbox_timerfsm # (
+    .TIMERBIT(16)
+  ) i_ab_fsm (
+    .clk_aon_i(clk_aon_i),
+    .rst_slow_ni(rst_slow_ni),
+    .trigger_i(pwrb_int_i),
+    .cfg_timer_i(cfg_auto_block_timer),
+    .cfg_l2h_en_i(1'b0),
+    .cfg_h2l_en_i(cfg_auto_block_en),
+    .timer_l2h_cond_met(),
+    .timer_h2l_cond_met(ab_cond_met)
+  );
+
+  assign pwrb_out_hw = pwrb_int;
+  assign key0_out_hw = (ab_cond_met & cfg_key0_o_sel) ? cfg_key0_o_q : key0_int;
+  assign key1_out_hw = (ab_cond_met & cfg_key1_o_sel) ? cfg_key1_o_q : key1_int;
+  assign key2_out_hw = (ab_cond_met & cfg_key2_o_sel) ? cfg_key2_o_q : key2_int;
+
+endmodule
diff --git a/hw/ip/rbox/rtl/rbox_combo.sv b/hw/ip/rbox/rtl/rbox_combo.sv
new file mode 100644
index 0000000..f2fd25d
--- /dev/null
+++ b/hw/ip/rbox/rtl/rbox_combo.sv
@@ -0,0 +1,392 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description: RBOX combo Module
+//
+module rbox_combo import rbox_reg_pkg::*; (
+  input  clk_aon_i,
+  input  rst_slow_ni,
+  input  clk_i,
+  input  rst_ni,
+
+  input  pwrb_int,
+  input  key0_int,
+  input  key1_int,
+  input  key2_int,
+  input  ac_present_int,
+  input  cio_ec_rst_l_i,
+
+  input  rbox_reg2hw_ec_rst_ctl_reg_t ec_rst_ctl_i,
+  input  rbox_reg2hw_key_intr_debounce_ctl_reg_t key_intr_debounce_ctl_i,
+  input  rbox_reg2hw_com_sel_ctl_mreg_t [NumCombo-1:0] com_sel_ctl_i,
+  input  rbox_reg2hw_com_det_ctl_mreg_t [NumCombo-1:0] com_det_ctl_i,
+  input  rbox_reg2hw_com_out_ctl_mreg_t [NumCombo-1:0] com_out_ctl_i,
+
+  output rbox_hw2reg_combo_intr_status_reg_t combo_intr_status_o,
+  output rbox_combo_intr,
+
+  output bat_disable_hw,
+  output gsc_rst_o,
+  output ec_rst_l_hw
+);
+
+  //There are four possible combos
+  //Each key combo can select different triggers
+  logic [NumCombo-1:0] cfg_key0_in_sel_com;
+  logic [NumCombo-1:0] cfg_key1_in_sel_com;
+  logic [NumCombo-1:0] cfg_key2_in_sel_com;
+  logic [NumCombo-1:0] cfg_pwrb_in_sel_com;
+  logic [NumCombo-1:0] cfg_ac_present_sel_com;
+
+  logic [31:0] cfg_combo_timer [NumCombo];
+  logic [15:0] cfg_debounce_timer;
+
+  logic [NumCombo-1:0] load_combo_timer;
+  logic load_debounce_timer;
+
+  logic [31:0] cfg_combo_timer_d [NumCombo];
+  logic [15:0] cfg_debounce_timer_d;
+
+  logic [NumCombo-1:0] cfg_bat_disable_com;
+  logic [NumCombo-1:0] cfg_intr_com;
+  logic [NumCombo-1:0] cfg_ec_rst_com;
+  logic [NumCombo-1:0] cfg_gsc_rst_com;
+
+  logic pwrb_int_i;
+  logic key0_int_i, key1_int_i, key2_int_i;
+  logic ac_present_int_i;
+
+  logic [NumCombo-1:0] trigger_h;
+  logic [NumCombo-1:0] trigger_l;
+  logic [NumCombo-1:0] cfg_combo_en;
+  logic [NumCombo-1:0] combo_det;
+
+  logic [NumCombo-1:0] combo_bat_disable;
+  logic [NumCombo-1:0] combo_intr_pulse;
+  logic [NumCombo-1:0] combo_ec_rst_l;
+  logic [NumCombo-1:0] combo_gsc_rst;
+
+  logic ec_rst_l_int_i;
+
+  logic combo0_h2l_intr, combo1_h2l_intr, combo2_h2l_intr, combo3_h2l_intr;
+
+  //synchronize between GPIO and always-on(200KHz)
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_ec_rst_l_int_i (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(cio_ec_rst_l_i),
+    .q_o(ec_rst_l_int_i)
+  );
+
+  //synchronize between cfg(24MHz) and always-on(200KHz)
+  for (genvar k = 0 ; k < NumCombo ; k++) begin : gen_com_sel
+    prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_com_sel_key0 (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(com_sel_ctl_i[k].key0_in_sel.q),
+    .q_o(cfg_key0_in_sel_com[k])
+  );
+
+    prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_com_sel_key1 (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(com_sel_ctl_i[k].key1_in_sel.q),
+    .q_o(cfg_key1_in_sel_com[k])
+  );
+
+    prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_com_sel_key2 (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(com_sel_ctl_i[k].key2_in_sel.q),
+    .q_o(cfg_key2_in_sel_com[k])
+  );
+
+    prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_com_sel_pwrb (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(com_sel_ctl_i[k].pwrb_in_sel.q),
+    .q_o(cfg_pwrb_in_sel_com[k])
+  );
+
+    prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_com_sel_ac_present (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(com_sel_ctl_i[k].ac_present_sel.q),
+    .q_o(cfg_ac_present_sel_com[k])
+  );
+  end
+
+  for (genvar k = 0 ; k < NumCombo ; k++) begin : gen_com_det
+    prim_fifo_async #(
+    .Width(32),
+    .Depth(2)
+  ) i_cfg_combo_timer (
+    .clk_wr_i  (clk_i),
+    .rst_wr_ni (rst_ni),
+    .wvalid_i  (com_det_ctl_i[k].qe),
+    .wready_o  (),
+    .wdata_i   (com_det_ctl_i[k].q),
+    .wdepth_o  (),
+
+    .clk_rd_i  (clk_aon_i),
+    .rst_rd_ni (rst_slow_ni),
+    .rvalid_o  (load_combo_timer[k]),
+    .rready_i  (1'b1),
+    .rdata_o   (cfg_combo_timer_d[k]),
+    .rdepth_o  ()
+  );
+
+    always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_cfg_combo_timer_reg
+      if (!rst_slow_ni) begin
+        cfg_combo_timer[k]    <= '0;
+      end else if (load_combo_timer[k]) begin
+        cfg_combo_timer[k]    <= cfg_combo_timer_d[k];
+      end
+    end
+  end
+
+  prim_fifo_async #(
+    .Width(16),
+    .Depth(2)
+  ) i_cfg_debounce_timer (
+    .clk_wr_i  (clk_i),
+    .rst_wr_ni (rst_ni),
+    .wvalid_i  (key_intr_debounce_ctl_i.qe),
+    .wready_o  (),
+    .wdata_i   (key_intr_debounce_ctl_i.q),
+    .wdepth_o  (),
+
+    .clk_rd_i  (clk_aon_i),
+    .rst_rd_ni (rst_slow_ni),
+    .rvalid_o  (load_debounce_timer),
+    .rready_i  (1'b1),
+    .rdata_o   (cfg_debounce_timer_d),
+    .rdepth_o  ()
+  );
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_cfg_debounce_timer_reg
+    if (!rst_slow_ni) begin
+      cfg_debounce_timer    <= '0;
+    end else if (load_debounce_timer) begin
+      cfg_debounce_timer    <= cfg_debounce_timer_d;
+    end
+  end
+
+  for (genvar k = 0 ; k < NumCombo ; k++) begin : gen_com_out
+    prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_com_bat_disable (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(com_out_ctl_i[k].bat_disable.q),
+    .q_o(cfg_bat_disable_com[k])
+  );
+
+    prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_com_intr (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(com_out_ctl_i[k].interrupt.q),
+    .q_o(cfg_intr_com[k])
+  );
+
+    prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_com_ec_rst (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(com_out_ctl_i[k].ec_rst.q),
+    .q_o(cfg_ec_rst_com[k])
+  );
+
+    prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_com_gsc_rst (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(com_out_ctl_i[k].gsc_rst.q),
+    .q_o(cfg_gsc_rst_com[k])
+  );
+  end
+
+  //synchronize between GPIO and always-on(200KHz)
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_pwrb_int_i (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pwrb_int),
+    .q_o(pwrb_int_i)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_key0_int_i (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key0_int),
+    .q_o(key0_int_i)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_key1_int_i (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key1_int),
+    .q_o(key1_int_i)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_key2_int_i (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key2_int),
+    .q_o(key2_int_i)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_ac_present_int_i (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(ac_present_int),
+    .q_o(ac_present_int_i)
+  );
+
+  //generate the trigger for each combo
+  for (genvar k = 0 ; k < NumCombo ; k++) begin : gen_combo_trigger
+    rbox_combotrg i_combo_trg (
+      .cfg_in0_sel(cfg_pwrb_in_sel_com[k]),
+      .cfg_in1_sel(cfg_key0_in_sel_com[k]),
+      .cfg_in2_sel(cfg_key1_in_sel_com[k]),
+      .cfg_in3_sel(cfg_key2_in_sel_com[k]),
+      .cfg_in4_sel(cfg_ac_present_sel_com[k]),
+      .in0(pwrb_int_i),
+      .in1(key0_int_i),
+      .in2(key1_int_i),
+      .in3(key2_int_i),
+      .in4(ac_present_int_i),
+      .trigger_h_o(trigger_h[k]),
+      .trigger_l_o(trigger_l[k])
+    );
+    assign cfg_combo_en[k] = cfg_pwrb_in_sel_com[k] | cfg_key0_in_sel_com[k] |
+      cfg_key1_in_sel_com[k] | cfg_key2_in_sel_com[k] |
+      cfg_ac_present_sel_com[k];
+  end
+
+  //Instantiate the combo detection state machine
+  for (genvar k = 0 ; k < NumCombo ; k++) begin : gen_combofsm
+    rbox_combofsm # (
+      .TIMER1BIT(16),
+      .TIMER2BIT(32)
+    ) i_combo_fsm (
+      .clk_aon_i(clk_aon_i),
+      .rst_slow_ni(rst_slow_ni),
+      .trigger_h_i(trigger_h[k]),
+      .trigger_l_i(trigger_l[k]),
+      .cfg_timer1_i(cfg_debounce_timer),
+      .cfg_timer2_i(cfg_combo_timer[k]),
+      .cfg_h2l_en_i(cfg_combo_en[k]),
+      .timer_h2l_cond_met(combo_det[k])
+    );
+  end
+
+  //Instantiate the combo action module
+  for (genvar k = 0 ; k < NumCombo ; k++) begin : gen_combo_act
+    rbox_comboact i_combo_act (
+      .clk_aon_i(clk_aon_i),
+      .rst_slow_ni(rst_slow_ni),
+      .clk_i(clk_i),
+      .rst_ni(rst_ni),
+      .cfg_intr_en(cfg_intr_com[k]),
+      .cfg_bat_disable_en(cfg_bat_disable_com[k]),
+      .cfg_ec_rst_en(cfg_ec_rst_com[k]),
+      .cfg_gsc_rst_en(cfg_gsc_rst_com[k]),
+      .combo_det(combo_det[k]),
+      .ec_rst_l_i(ec_rst_l_int_i),
+      .ec_rst_ctl_i(ec_rst_ctl_i),
+      .combo_intr_pulse(combo_intr_pulse[k]),
+      .bat_disable_o(combo_bat_disable[k]),
+      .gsc_rst_o(combo_gsc_rst[k]),
+      .ec_rst_l_o(combo_ec_rst_l[k])
+   );
+  end
+
+  //bat_disable
+  //If any combo triggers bat_disable, assert the signal
+  assign bat_disable_hw = |(combo_bat_disable);
+
+  //If any combo triggers GSC or EC RST(active low), assert the signal
+  assign gsc_rst_o = |(combo_gsc_rst);
+  assign ec_rst_l_hw = &(combo_ec_rst_l);
+
+  //Synchronize from 200KHz always-onclock to 24MHz cfg clock
+  prim_pulse_sync i_combo0_intr (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (combo_intr_pulse[0]),
+    .dst_pulse_o (combo0_h2l_intr)
+  );
+
+  assign combo_intr_status_o.combo0_h2l.de = combo0_h2l_intr;
+
+  prim_pulse_sync i_combo1_intr (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (combo_intr_pulse[1]),
+    .dst_pulse_o (combo1_h2l_intr)
+  );
+
+  assign combo_intr_status_o.combo1_h2l.de = combo1_h2l_intr;
+
+  prim_pulse_sync i_combo2_intr (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (combo_intr_pulse[2]),
+    .dst_pulse_o (combo2_h2l_intr)
+  );
+
+  assign combo_intr_status_o.combo2_h2l.de = combo2_h2l_intr;
+
+  prim_pulse_sync i_combo3_intr (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (combo_intr_pulse[3]),
+    .dst_pulse_o (combo3_h2l_intr)
+  );
+
+  assign combo_intr_status_o.combo3_h2l.de = combo3_h2l_intr;
+
+  assign rbox_combo_intr = combo0_h2l_intr | combo1_h2l_intr | combo2_h2l_intr | combo3_h2l_intr;
+
+  //To write into interrupt status register
+  assign combo_intr_status_o.combo0_h2l.d = 1'b1;
+  assign combo_intr_status_o.combo1_h2l.d = 1'b1;
+  assign combo_intr_status_o.combo2_h2l.d = 1'b1;
+  assign combo_intr_status_o.combo3_h2l.d = 1'b1;
+
+endmodule
diff --git a/hw/ip/rbox/rtl/rbox_comboact.sv b/hw/ip/rbox/rtl/rbox_comboact.sv
new file mode 100644
index 0000000..930c2db
--- /dev/null
+++ b/hw/ip/rbox/rtl/rbox_comboact.sv
@@ -0,0 +1,162 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description: RBOX combo action Module
+//
+module rbox_comboact import rbox_reg_pkg::*; (
+  input  clk_aon_i,
+  input  rst_slow_ni,
+  input  clk_i,
+  input  rst_ni,
+
+  input  cfg_intr_en,
+  input  cfg_bat_disable_en,
+  input  cfg_ec_rst_en,
+  input  cfg_gsc_rst_en,
+  input  combo_det,
+  input  ec_rst_l_i,
+
+  input  rbox_reg2hw_ec_rst_ctl_reg_t ec_rst_ctl_i,
+
+  output combo_intr_pulse,
+  output bat_disable_o,
+  output gsc_rst_o,
+  output ec_rst_l_o
+);
+
+  logic [15:0] cfg_ec_rst_timer;
+  logic        load_ec_rst_timer;
+  logic [15:0] cfg_ec_rst_timer_d;
+
+  logic combo_det_q;
+  logic combo_gsc_pulse;
+  logic combo_bat_disable_pulse;
+  logic bat_disable_q, bat_disable_d;
+  logic gsc_rst_q, gsc_rst_d;
+  logic combo_ec_rst_pulse;
+  logic ec_rst_l_q, ec_rst_l_d;
+
+  logic [15:0] timer_cnt_d, timer_cnt_q;
+  logic timer_cnt_clr, timer_cnt_en;
+
+  logic ec_rst_l_int, ec_rst_l_det;
+
+  //delay the level signal to generate a pulse
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_combo_det
+    if (!rst_slow_ni) begin
+      combo_det_q    <= 1'b0;
+    end else begin
+      combo_det_q    <= combo_det;
+    end
+  end
+
+  //bat_disable logic
+  assign combo_bat_disable_pulse = cfg_bat_disable_en && (combo_det_q == 1'b0) &&
+    (combo_det == 1'b1);
+
+  assign bat_disable_d = combo_bat_disable_pulse ? 1'b1 : bat_disable_q;
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_combo_bat_disable
+    if (!rst_slow_ni) begin
+      bat_disable_q    <= 1'b0;
+    end else begin
+      bat_disable_q    <= bat_disable_d;
+    end
+  end
+
+  assign bat_disable_o = bat_disable_q;
+
+  //Interrupt logic
+  assign combo_intr_pulse = cfg_intr_en && (combo_det_q == 1'b0) && (combo_det == 1'b1);
+
+  //ec_rst_logic
+  //synchronize between cfg(24MHz) and always-on(200KHz)
+  prim_fifo_async #(
+    .Width(16),
+    .Depth(2)
+  ) i_cfg_ec_rst_pulse (
+    .clk_wr_i  (clk_i),
+    .rst_wr_ni (rst_ni),
+    .wvalid_i  (ec_rst_ctl_i.qe),
+    .wready_o  (),
+    .wdata_i   (ec_rst_ctl_i.q),
+    .wdepth_o  (),
+
+    .clk_rd_i  (clk_aon_i),
+    .rst_rd_ni (rst_slow_ni),
+    .rvalid_o  (load_ec_rst_timer),
+    .rready_i  (1'b1),
+    .rdata_o   (cfg_ec_rst_timer_d),
+    .rdepth_o  ()
+  );
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_cfg_ec_rst_timer_reg
+    if (!rst_slow_ni) begin
+      cfg_ec_rst_timer    <= '0;
+    end else if (load_ec_rst_timer) begin
+      cfg_ec_rst_timer    <= cfg_ec_rst_timer_d;
+    end
+  end
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_ec_rst_l_int
+    if (!rst_slow_ni) begin
+      ec_rst_l_int    <= 1'b1;//active low signal
+    end else begin
+      ec_rst_l_int    <= ec_rst_l_i;
+    end
+  end
+
+  //ec_rst_l_i high->low detection
+  assign ec_rst_l_det = (ec_rst_l_int == 1'b1) && (ec_rst_l_i == 1'b0);
+
+  //combo with EC RST CFG enable
+  assign combo_ec_rst_pulse = cfg_ec_rst_en && (combo_det_q == 1'b0) && (combo_det == 1'b1);
+
+  //GSC reset will also reset EC
+  assign ec_rst_l_d = (combo_ec_rst_pulse | combo_gsc_pulse | ec_rst_l_det) ? 1'b0 :
+          timer_cnt_clr ? 1'b1 : ec_rst_l_q;
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_combo_ec_rst_l
+    if (!rst_slow_ni) begin
+      ec_rst_l_q    <= 1'b0;//asserted when power-on-reset is asserted
+    end else begin
+      ec_rst_l_q    <= ec_rst_l_d;
+    end
+  end
+
+  assign timer_cnt_en = (ec_rst_l_q == 1'b0);
+
+  assign timer_cnt_clr = (ec_rst_l_q == 1'b0) && (timer_cnt_q == cfg_ec_rst_timer);
+
+  assign timer_cnt_d = (timer_cnt_en) ? timer_cnt_q + 1'b1 : timer_cnt_q;
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: timer_cnt_regs
+    if (!rst_slow_ni) begin
+      timer_cnt_q    <= '0;
+    end
+    else if (timer_cnt_clr) begin
+      timer_cnt_q <= '0;
+    end else begin
+      timer_cnt_q <= timer_cnt_d;
+    end
+  end
+
+  assign ec_rst_l_o = ec_rst_l_q;
+
+  //gsc_rst_logic
+  assign combo_gsc_pulse = cfg_gsc_rst_en && (combo_det_q == 1'b0) && (combo_det == 1'b1);
+
+  assign gsc_rst_d = combo_gsc_pulse ? 1'b1 : gsc_rst_q;
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_combo_gsc_rst
+    if (!rst_slow_ni) begin
+      gsc_rst_q    <= 1'b0;
+    end else begin
+      gsc_rst_q    <= gsc_rst_d;
+    end
+  end
+
+  assign gsc_rst_o = gsc_rst_q;
+
+endmodule
diff --git a/hw/ip/rbox/rtl/rbox_combofsm.sv b/hw/ip/rbox/rtl/rbox_combofsm.sv
new file mode 100644
index 0000000..67ed3d4
--- /dev/null
+++ b/hw/ip/rbox/rtl/rbox_combofsm.sv
@@ -0,0 +1,157 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description RBOX combo detection FSM module
+
+module rbox_combofsm #(
+  parameter int unsigned TIMER1BIT = 16,
+  parameter int unsigned TIMER2BIT = 32
+  ) (
+  input                clk_aon_i,
+  input                rst_slow_ni,
+  input                trigger_h_i,//input vector is all "1"
+  input                trigger_l_i,//input vector is all "0"
+  input [TIMER1BIT-1:0] cfg_timer1_i,//debounce
+  input [TIMER2BIT-1:0] cfg_timer2_i,//detection
+  input                cfg_h2l_en_i,
+  output logic         timer_h2l_cond_met
+
+);
+
+  logic trigger_h_q, trigger_l_q;
+  logic trigger_h2l, trigger_l2h, trigger_h2h, trigger_l2l;
+
+  logic [TIMER1BIT-1:0] timer1_cnt_d, timer1_cnt_q;
+  logic timer1_cnt_clr, timer1_cnt_en;
+  logic [TIMER2BIT-1:0] timer2_cnt_d, timer2_cnt_q;
+  logic timer2_cnt_clr, timer2_cnt_en;
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_trigger_h_reg
+    if (!rst_slow_ni) begin
+      trigger_h_q    <= 1'b0;
+    end else begin
+      trigger_h_q    <= trigger_h_i;
+    end
+  end
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_trigger_l_reg
+    if (!rst_slow_ni) begin
+      trigger_l_q    <= 1'b0;
+    end else begin
+      trigger_l_q    <= trigger_l_i;
+    end
+  end
+
+  assign trigger_h2l = (trigger_h_q == 1'b1) && (trigger_l_i == 1'b1);
+  assign trigger_l2h = (trigger_l_q == 1'b1) && (trigger_h_i == 1'b1);
+  assign trigger_h2h = (trigger_h_q == 1'b1) && (trigger_h_i == 1'b1);
+  assign trigger_l2l = (trigger_l_q == 1'b1) && (trigger_l_i == 1'b1);
+
+  //Four-state FSM
+  //IDLE->WAIT1->WAIT2->DONE
+  //FSM will detect a H2L transition to enter the wait1 state
+  //debounce timer defines the time for input to stablize
+  //FSM will check the input after the debounce period
+  //If the input stays at low, enter the wait2 state
+  //Detection timer defines the time for input to be held(pressed)
+  //FSM will enter the done state after the detection period
+  typedef enum logic [1:0] {
+                            IDLE = 2'h0,
+                            WAIT1 = 2'h1,
+                            WAIT2 = 2'h2,
+                            DONE = 2'h3
+                            } timer_state_e;
+
+  timer_state_e timer_state_q, timer_state_d;
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_timer_state_reg
+    if (!rst_slow_ni) begin
+      timer_state_q    <= IDLE;
+    end else begin
+      timer_state_q    <= timer_state_d;
+    end
+  end
+
+  assign timer1_cnt_d = (timer1_cnt_en) ? timer1_cnt_q + 1'b1 : timer1_cnt_q;
+  assign timer2_cnt_d = (timer2_cnt_en) ? timer2_cnt_q + 1'b1 : timer2_cnt_q;
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_timer1_cnt_reg
+    if (!rst_slow_ni) begin
+      timer1_cnt_q    <= '0;
+    end
+    else if (timer1_cnt_clr) begin
+      timer1_cnt_q <= '0;
+    end else begin
+      timer1_cnt_q <= timer1_cnt_d;
+    end
+  end
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_timer2_cnt_reg
+    if (!rst_slow_ni) begin
+      timer2_cnt_q    <= '0;
+    end
+    else if (timer2_cnt_clr) begin
+      timer2_cnt_q <= '0;
+    end else begin
+      timer2_cnt_q <= timer2_cnt_d;
+    end
+  end
+
+  always_comb begin: timer_fsm
+    timer_state_d = timer_state_q;
+    //outputs
+    timer_h2l_cond_met = 1'b0;
+    timer1_cnt_clr = 1'b0;
+    timer1_cnt_en = 1'b0;
+    timer2_cnt_clr = 1'b0;
+    timer2_cnt_en = 1'b0;
+
+    unique case (timer_state_q)
+      IDLE: begin
+        if (cfg_h2l_en_i &&  trigger_h2l) begin
+          timer_state_d = WAIT1;
+        end
+      end
+
+      WAIT1: begin
+        if (timer1_cnt_q != cfg_timer1_i) begin
+          timer1_cnt_en = 1'b1;
+        end
+        else if (!trigger_l2l && (timer1_cnt_q == cfg_timer1_i)) begin
+          timer_state_d = IDLE;
+          timer1_cnt_clr = 1'b1;
+        end
+        else if (trigger_l2l && (timer1_cnt_q == cfg_timer1_i)) begin
+          timer_state_d = WAIT2;
+          timer1_cnt_clr = 1'b1;
+        end
+      end
+
+      WAIT2: begin
+        if (timer2_cnt_q != cfg_timer2_i) begin
+          timer2_cnt_en = 1'b1;
+        end
+        else if (!trigger_l2l && (timer2_cnt_q == cfg_timer2_i)) begin
+          timer_state_d = IDLE;
+          timer2_cnt_clr = 1'b1;
+        end
+        else if (trigger_l2l && (timer2_cnt_q == cfg_timer2_i)) begin
+          timer_state_d = DONE;
+          timer2_cnt_clr = 1'b1;
+        end
+      end
+
+      DONE: begin
+        if (trigger_l2l) begin
+          timer_h2l_cond_met = 1'b1;
+        end
+        else if (trigger_l2h) begin
+          timer_state_d = IDLE;
+        end
+      end
+      default: timer_state_d = IDLE;
+    endcase
+  end
+
+endmodule
diff --git a/hw/ip/rbox/rtl/rbox_combotrg.sv b/hw/ip/rbox/rtl/rbox_combotrg.sv
new file mode 100644
index 0000000..20cb809
--- /dev/null
+++ b/hw/ip/rbox/rtl/rbox_combotrg.sv
@@ -0,0 +1,158 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description RBOX combo trigger  module
+
+module rbox_combotrg (
+  input                cfg_in0_sel,
+  input                cfg_in1_sel,
+  input                cfg_in2_sel,
+  input                cfg_in3_sel,
+  input                cfg_in4_sel,
+  input                in0,
+  input                in1,
+  input                in2,
+  input                in3,
+  input                in4,
+  output logic         trigger_h_o,
+  output logic         trigger_l_o
+);
+
+  logic [4:0] cfg_input_sel;
+
+  assign cfg_input_sel = {cfg_in0_sel, cfg_in1_sel, cfg_in2_sel, cfg_in3_sel, cfg_in4_sel};
+
+  always_comb begin: trigger_combo
+
+    unique case (cfg_input_sel)
+      5'b00001: begin
+         trigger_h_o = (in4 == 1'b1);
+         trigger_l_o = (in4 == 1'b0);
+      end
+      5'b00010: begin
+         trigger_h_o = (in3 == 1'b1);
+         trigger_l_o = (in3 == 1'b0);
+      end
+      5'b00011: begin
+         trigger_h_o = (in3 == 1'b1) && (in4 == 1'b1);
+         trigger_l_o = (in3 == 1'b0) && (in4 == 1'b0);
+      end
+      5'b00100: begin
+         trigger_h_o = (in2 == 1'b1);
+         trigger_l_o = (in2 == 1'b0);
+      end
+      5'b00101: begin
+         trigger_h_o = (in2 == 1'b1) && (in4 == 1'b1);
+         trigger_l_o = (in2 == 1'b0) && (in4 == 1'b0);
+      end
+      5'b00111: begin
+         trigger_h_o = (in2 == 1'b1) && (in3 == 1'b1) && (in4 == 1'b1);
+         trigger_l_o = (in2 == 1'b0) && (in3 == 1'b0) && (in4 == 1'b0);
+      end
+      5'b01000: begin
+         trigger_h_o = (in1 == 1'b1);
+         trigger_l_o = (in1 == 1'b0);
+      end
+      5'b01001: begin
+         trigger_h_o = (in1 == 1'b1) && (in4 == 1'b1);
+         trigger_l_o = (in1 == 1'b0) && (in4 == 1'b0);
+      end
+      5'b01010: begin
+         trigger_h_o = (in1 == 1'b1) && (in3 == 1'b1);
+         trigger_l_o = (in1 == 1'b0) && (in3 == 1'b0);
+      end
+      5'b01011: begin
+         trigger_h_o = (in1 == 1'b1) && (in3 == 1'b1) && (in4 == 1'b1);
+         trigger_l_o = (in1 == 1'b0) && (in3 == 1'b0) && (in4 == 1'b0);
+      end
+      5'b01100: begin
+         trigger_h_o = (in1 == 1'b1) && (in2 == 1'b1);
+         trigger_l_o = (in1 == 1'b0) && (in2 == 1'b0);
+      end
+      5'b01101: begin
+         trigger_h_o = (in1 == 1'b1) && (in2 == 1'b1) && (in4 == 1'b1);
+         trigger_l_o = (in1 == 1'b0) && (in2 == 1'b0) && (in4 == 1'b0);
+      end
+      5'b01110: begin
+         trigger_h_o = (in1 == 1'b1) && (in2 == 1'b1) && (in3 == 1'b1);
+         trigger_l_o = (in1 == 1'b0) && (in2 == 1'b0) && (in3 == 1'b0);
+      end
+      5'b01111: begin
+         trigger_h_o = (in1 == 1'b1) && (in2 == 1'b1) && (in3 == 1'b1) && (in4 == 1'b1);
+         trigger_l_o = (in1 == 1'b0) && (in2 == 1'b0) && (in3 == 1'b0) && (in4 == 1'b0);
+      end
+      5'b10000: begin
+         trigger_h_o = (in0 == 1'b1);
+         trigger_l_o = (in0 == 1'b0);
+      end
+      5'b10001: begin
+         trigger_h_o = (in0 == 1'b1) && (in4 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in4 == 1'b0);
+      end
+      5'b10010: begin
+         trigger_h_o = (in0 == 1'b1) && (in3 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in3 == 1'b0);
+      end
+      5'b10011: begin
+         trigger_h_o = (in0 == 1'b1) && (in3 == 1'b1) && (in4 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in3 == 1'b0) && (in4 == 1'b0);
+      end
+      5'b10100: begin
+         trigger_h_o = (in0 == 1'b1) && (in2 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in2 == 1'b0);
+      end
+      5'b10101: begin
+         trigger_h_o = (in0 == 1'b1) && (in2 == 1'b1) && (in4 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in2 == 1'b0) && (in4 == 1'b0);
+      end
+      5'b10110: begin
+         trigger_h_o = (in0 == 1'b1) && (in2 == 1'b1) && (in3 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in2 == 1'b0) && (in3 == 1'b0);
+      end
+      5'b10111: begin
+         trigger_h_o = (in0 == 1'b1) && (in2 == 1'b1) && (in3 == 1'b1) && (in4 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in2 == 1'b0) && (in3 == 1'b0) && (in4 == 1'b0);
+      end
+      5'b11000: begin
+         trigger_h_o = (in0 == 1'b1) && (in1 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in1 == 1'b0);
+      end
+      5'b11001: begin
+         trigger_h_o = (in0 == 1'b1) && (in1 == 1'b1) && (in4 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in1 == 1'b0) && (in4 == 1'b0);
+      end
+      5'b11010: begin
+         trigger_h_o = (in0 == 1'b1) && (in1 == 1'b1) && (in3 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in1 == 1'b0) && (in3 == 1'b0);
+      end
+      5'b11011: begin
+         trigger_h_o = (in0 == 1'b1) && (in1 == 1'b1) && (in3 == 1'b1) && (in4 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in1 == 1'b0) && (in3 == 1'b0) && (in4 == 1'b0);
+      end
+      5'b11100: begin
+         trigger_h_o = (in0 == 1'b1) && (in1 == 1'b1) && (in2 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in1 == 1'b0) && (in2 == 1'b0);
+      end
+      5'b11101: begin
+         trigger_h_o = (in0 == 1'b1) && (in1 == 1'b1) && (in2 == 1'b1) && (in4 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in1 == 1'b0) && (in2 == 1'b0) && (in4 == 1'b0);
+      end
+      5'b11110: begin
+         trigger_h_o = (in0 == 1'b1) && (in1 == 1'b1) && (in2 == 1'b1) && (in3 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in1 == 1'b0) && (in2 == 1'b0) && (in3 == 1'b0);
+      end
+      5'b11111: begin
+         trigger_h_o = (in0 == 1'b1) && (in1 == 1'b1) && (in2 == 1'b1) && (in3 == 1'b1) &&
+           (in4 == 1'b1);
+         trigger_l_o = (in0 == 1'b0) && (in1 == 1'b0) && (in2 == 1'b0) && (in3 == 1'b0) &&
+           (in4 == 1'b0);
+      end
+      default: begin
+         trigger_h_o = 1'b0;
+         trigger_l_o = 1'b0;
+      end
+    endcase
+  end
+
+endmodule
diff --git a/hw/ip/rbox/rtl/rbox_intr.sv b/hw/ip/rbox/rtl/rbox_intr.sv
new file mode 100644
index 0000000..2355b30
--- /dev/null
+++ b/hw/ip/rbox/rtl/rbox_intr.sv
@@ -0,0 +1,37 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description: RBOX interrupt Module
+//
+module rbox_intr import rbox_reg_pkg::*; (
+  input  clk_i,
+  input  rst_ni,
+  input  rbox_combo_intr,
+  input  rbox_key_intr,
+  input  rbox_reg2hw_intr_state_reg_t intr_state_i,
+  input  rbox_reg2hw_intr_enable_reg_t intr_enable_i,
+  input  rbox_reg2hw_intr_test_reg_t intr_test_i,
+  output rbox_hw2reg_intr_state_reg_t intr_state_o,
+  output rbox_intr_o
+);
+
+  logic rbox_event;
+
+  assign rbox_event = rbox_combo_intr | rbox_key_intr;
+
+  // instantiate interrupt hardware primitive
+  prim_intr_hw #(.Width(1)) i_rbox_intr_o (
+    .clk_i(clk_i),
+    .rst_ni(rst_ni),
+    .event_intr_i           (rbox_event),
+    .reg2hw_intr_enable_q_i (intr_enable_i.q),
+    .reg2hw_intr_test_q_i   (intr_test_i.q),
+    .reg2hw_intr_test_qe_i  (intr_test_i.qe),
+    .reg2hw_intr_state_q_i  (intr_state_i.q),
+    .hw2reg_intr_state_de_o (intr_state_o.de),
+    .hw2reg_intr_state_d_o  (intr_state_o.d),
+    .intr_o                 (rbox_intr_o)
+  );
+
+endmodule
diff --git a/hw/ip/rbox/rtl/rbox_inv.sv b/hw/ip/rbox/rtl/rbox_inv.sv
new file mode 100644
index 0000000..cb63c6c
--- /dev/null
+++ b/hw/ip/rbox/rtl/rbox_inv.sv
@@ -0,0 +1,154 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description: RBOX pin inversion Module
+//
+
+module rbox_inv import rbox_reg_pkg::*; (
+  input  clk_aon_i,
+  input  rst_slow_ni,
+
+  input  cio_pwrb_in_i,
+  input  cio_key0_in_i,
+  input  cio_key1_in_i,
+  input  cio_key2_in_i,
+  input  cio_ac_present_i,
+
+  input  pwrb_out_int,
+  input  key0_out_int,
+  input  key1_out_int,
+  input  key2_out_int,
+  input  bat_disable_int,
+
+  input  rbox_reg2hw_key_invert_ctl_reg_t key_invert_ctl_i,
+
+  output pwrb_int,
+  output key0_int,
+  output key1_int,
+  output key2_int,
+  output ac_present_int,
+
+  output cio_bat_disable_o,
+  output cio_pwrb_out_o,
+  output cio_key0_out_o,
+  output cio_key1_out_o,
+  output cio_key2_out_o
+
+);
+
+  logic  cfg_pwrb_i_inv;
+  logic  cfg_key0_i_inv;
+  logic  cfg_key1_i_inv;
+  logic  cfg_key2_i_inv;
+  logic  cfg_ac_present_i_inv;
+  logic  cfg_pwrb_o_inv;
+  logic  cfg_key0_o_inv;
+  logic  cfg_key1_o_inv;
+  logic  cfg_key2_o_inv;
+  logic  cfg_bat_disable_o_inv;
+
+  //synchronize between cfg(24MHz) and always-on(200KHz)
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_pwrb_i_inv (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_invert_ctl_i.pwrb_in.q),
+    .q_o(cfg_pwrb_i_inv)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key0_i_inv (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_invert_ctl_i.key0_in.q),
+    .q_o(cfg_key0_i_inv)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key1_i_inv (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_invert_ctl_i.key1_in.q),
+    .q_o(cfg_key1_i_inv)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key2_i_inv (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_invert_ctl_i.key2_in.q),
+    .q_o(cfg_key2_i_inv)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_ac_present_i_inv (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_invert_ctl_i.ac_present.q),
+    .q_o(cfg_ac_present_i_inv)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_pwrb_o_inv (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_invert_ctl_i.pwrb_out.q),
+    .q_o(cfg_pwrb_o_inv)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key0_o_inv (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_invert_ctl_i.key0_out.q),
+    .q_o(cfg_key0_o_inv)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key1_o_inv (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_invert_ctl_i.key1_out.q),
+    .q_o(cfg_key1_o_inv)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key2_o_inv (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_invert_ctl_i.key2_out.q),
+    .q_o(cfg_key2_o_inv)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_bat_disable_o_inv (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_invert_ctl_i.bat_disable.q),
+    .q_o(cfg_bat_disable_o_inv)
+  );
+
+  assign cio_pwrb_out_o = cfg_pwrb_o_inv ? ~pwrb_out_int : pwrb_out_int;
+  assign cio_key0_out_o = cfg_key0_o_inv ? ~key0_out_int : key0_out_int;
+  assign cio_key1_out_o = cfg_key1_o_inv ? ~key1_out_int : key1_out_int;
+  assign cio_key2_out_o = cfg_key2_o_inv ? ~key2_out_int : key2_out_int;
+  assign cio_bat_disable_o = cfg_bat_disable_o_inv ? ~bat_disable_int : bat_disable_int;
+
+  assign pwrb_int = cfg_pwrb_i_inv ? ~cio_pwrb_in_i : cio_pwrb_in_i;
+  assign key0_int = cfg_key0_i_inv ? ~cio_key0_in_i : cio_key0_in_i;
+  assign key1_int = cfg_key1_i_inv ? ~cio_key1_in_i : cio_key1_in_i;
+  assign key2_int = cfg_key2_i_inv ? ~cio_key2_in_i : cio_key2_in_i;
+  assign ac_present_int = cfg_ac_present_i_inv ? ~cio_ac_present_i : cio_ac_present_i;
+
+endmodule
diff --git a/hw/ip/rbox/rtl/rbox_keyfsm.sv b/hw/ip/rbox/rtl/rbox_keyfsm.sv
new file mode 100644
index 0000000..0a41a96
--- /dev/null
+++ b/hw/ip/rbox/rtl/rbox_keyfsm.sv
@@ -0,0 +1,155 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description RBOX key press and release FSM module
+
+module rbox_keyfsm #(
+  parameter int unsigned TIMERBIT = 16
+  ) (
+  input                clk_aon_i,
+  input                rst_slow_ni,
+  input                trigger_i,
+  input [TIMERBIT-1:0] cfg_timer_i,
+  input                cfg_l2h_en_i,
+  input                cfg_h2l_en_i,
+  output logic         timer_l2h_cond_met,
+  output logic         timer_h2l_cond_met
+
+);
+
+  logic trigger_q;
+  logic trigger_h2l, trigger_l2h, trigger_l2l, trigger_h2h;
+  logic trigger_tgl, trigger_sty;
+
+  logic [TIMERBIT-1:0] timer_cnt_d, timer_cnt_q;
+  logic timer_cnt_clr, timer_cnt_en;
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_trigger_reg
+    if (!rst_slow_ni) begin
+      trigger_q    <= 1'b0;
+    end else begin
+      trigger_q    <= trigger_i;
+    end
+  end
+
+  assign trigger_h2l = (trigger_q == 1'b1) && (trigger_i == 1'b0);
+  assign trigger_l2h = (trigger_q == 1'b0) && (trigger_i == 1'b1);
+  assign trigger_l2l = (trigger_q == 1'b0) && (trigger_i == 1'b0);
+  assign trigger_h2h = (trigger_q == 1'b1) && (trigger_i == 1'b1);
+  assign trigger_tgl = trigger_q != trigger_i;
+  assign trigger_sty = trigger_q == trigger_i;
+
+  //five-state FSM
+  //IDLE->WAITH2L->DONEH2L->WAITL2H->DONEL2H or
+  //IDLE->WAITL2H->DONEL2H->WAITH2L->DONEH2L
+  //The inputs can be inverted, hence two possible paths
+  //When a key or button is pressed, the non-inverted input signal goes from high to low.
+  //When a key or button is released, the non-inverted input signal goes from low to high.
+  //FSM will be able to detect a key or button being pressed then
+  //releaseed in one complete path
+  typedef enum logic [2:0] {
+                            IDLE = 3'h0,
+                            WAITL2H = 3'h1,
+                            WAITH2L = 3'h2,
+                            DONEL2H = 3'h3,
+                            DONEH2L = 3'h4
+                            } timer_state_e;
+
+  timer_state_e timer_state_q, timer_state_d;
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_timer_state_reg
+    if (!rst_slow_ni) begin
+      timer_state_q    <= IDLE;
+    end else begin
+      timer_state_q    <= timer_state_d;
+    end
+  end
+
+  assign timer_cnt_d = (timer_cnt_en) ? timer_cnt_q + 1'b1 : timer_cnt_q;
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_timer_cnt_reg
+    if (!rst_slow_ni) begin
+      timer_cnt_q    <= '0;
+    end
+    else if (timer_cnt_clr) begin
+      timer_cnt_q <= '0;
+    end else begin
+      timer_cnt_q <= timer_cnt_d;
+    end
+  end
+
+  always_comb begin: timer_fsm
+    timer_state_d = timer_state_q;
+    //outputs
+    timer_l2h_cond_met = 1'b0;
+    timer_h2l_cond_met = 1'b0;
+    timer_cnt_clr = 1'b0;
+    timer_cnt_en = 1'b0;
+
+    unique case (timer_state_q)
+      IDLE: begin
+        if (cfg_l2h_en_i &&  trigger_l2h) begin
+          timer_state_d = WAITL2H;
+        end
+        else if (cfg_h2l_en_i &&  trigger_h2l) begin
+          timer_state_d = WAITH2L;
+        end
+      end
+
+      WAITL2H: begin
+        if (timer_cnt_q != cfg_timer_i) begin
+          timer_cnt_en = 1'b1;
+        end
+        else if (!trigger_h2h && (timer_cnt_q == cfg_timer_i)) begin
+          timer_state_d = IDLE;
+          timer_cnt_clr = 1'b1;
+        end
+        else if (trigger_h2h && (timer_cnt_q == cfg_timer_i)) begin
+          timer_state_d = DONEL2H;
+          timer_cnt_clr = 1'b1;
+        end
+      end
+
+      DONEL2H: begin
+        if (trigger_h2h) begin
+          timer_l2h_cond_met = 1'b1;
+        end
+        else if (!cfg_h2l_en_i && trigger_h2l) begin
+          timer_state_d = IDLE;
+        end
+        else if (cfg_h2l_en_i && trigger_h2l) begin
+          timer_state_d = WAITH2L;
+        end
+      end
+
+      WAITH2L: begin
+        if (timer_cnt_q != cfg_timer_i) begin
+          timer_cnt_en = 1'b1;
+        end
+        else if (!trigger_l2l && (timer_cnt_q == cfg_timer_i)) begin
+          timer_state_d = IDLE;
+          timer_cnt_clr = 1'b1;
+        end
+        else if (trigger_l2l && (timer_cnt_q == cfg_timer_i)) begin
+          timer_state_d = DONEH2L;
+          timer_cnt_clr = 1'b1;
+        end
+      end
+
+      DONEH2L: begin
+        if (trigger_l2l) begin
+          timer_h2l_cond_met = 1'b1;
+        end
+        else if (!cfg_l2h_en_i && trigger_l2h) begin
+          timer_state_d = IDLE;
+        end
+        else if (cfg_l2h_en_i && trigger_l2h) begin
+          timer_state_d = WAITL2H;
+        end
+      end
+      default: timer_state_d = IDLE;
+    endcase
+  end
+
+endmodule
diff --git a/hw/ip/rbox/rtl/rbox_keyintr.sv b/hw/ip/rbox/rtl/rbox_keyintr.sv
new file mode 100644
index 0000000..906d7ff
--- /dev/null
+++ b/hw/ip/rbox/rtl/rbox_keyintr.sv
@@ -0,0 +1,609 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description: RBOX key-triggered interrupt Module
+//
+module rbox_keyintr import rbox_reg_pkg::*; (
+  input  clk_aon_i,
+  input  rst_slow_ni,
+  input  clk_i,
+  input  rst_ni,
+
+  input  pwrb_int,
+  input  key0_int,
+  input  key1_int,
+  input  key2_int,
+  input  ac_present_int,
+  input  cio_ec_rst_l_i,
+
+  input  rbox_reg2hw_key_intr_ctl_reg_t key_intr_ctl_i,
+  input  rbox_reg2hw_key_intr_debounce_ctl_reg_t key_intr_debounce_ctl_i,
+
+  output rbox_hw2reg_key_intr_status_reg_t key_intr_status_o,
+  output rbox_key_intr
+
+);
+
+  logic  cfg_pwrb_in_h2l;
+  logic  cfg_key0_in_h2l;
+  logic  cfg_key1_in_h2l;
+  logic  cfg_key2_in_h2l;
+  logic  cfg_ac_present_h2l;
+  logic  cfg_ec_rst_l_h2l;
+  logic  cfg_pwrb_in_l2h;
+  logic  cfg_key0_in_l2h;
+  logic  cfg_key1_in_l2h;
+  logic  cfg_key2_in_l2h;
+  logic  cfg_ac_present_l2h;
+  logic  cfg_ec_rst_l_l2h;
+
+  logic [15:0] cfg_key_intr_timer;
+  logic        load_key_intr_timer;
+  logic [15:0] cfg_key_intr_timer_d;
+
+  logic pwrb_int_i;
+  logic key0_int_i, key1_int_i, key2_int_i;
+  logic ac_present_int_i;
+  logic ec_rst_l_int_i;
+  logic pwrb_intr_h2l_det, pwrb_intr_h2l_det_q, pwrb_intr_h2l_pulse;
+  logic pwrb_intr_l2h_det, pwrb_intr_l2h_det_q, pwrb_intr_l2h_pulse;
+  logic key0_intr_h2l_det, key0_intr_h2l_det_q, key0_intr_h2l_pulse;
+  logic key0_intr_l2h_det, key0_intr_l2h_det_q, key0_intr_l2h_pulse;
+  logic key1_intr_h2l_det, key1_intr_h2l_det_q, key1_intr_h2l_pulse;
+  logic key1_intr_l2h_det, key1_intr_l2h_det_q, key1_intr_l2h_pulse;
+  logic key2_intr_h2l_det, key2_intr_h2l_det_q, key2_intr_h2l_pulse;
+  logic key2_intr_l2h_det, key2_intr_l2h_det_q, key2_intr_l2h_pulse;
+  logic ac_present_intr_h2l_det, ac_present_intr_h2l_det_q, ac_present_intr_h2l_pulse;
+  logic ac_present_intr_l2h_det, ac_present_intr_l2h_det_q, ac_present_intr_l2h_pulse;
+  logic ec_rst_l_intr_h2l_det, ec_rst_l_intr_h2l_det_q, ec_rst_l_intr_h2l_pulse;
+  logic ec_rst_l_intr_l2h_det, ec_rst_l_intr_l2h_det_q, ec_rst_l_intr_l2h_pulse;
+
+  logic pwrb_h2l_intr, pwrb_l2h_intr;
+  logic key0_in_h2l_intr, key0_in_l2h_intr;
+  logic key1_in_h2l_intr, key1_in_l2h_intr;
+  logic key2_in_h2l_intr, key2_in_l2h_intr;
+  logic ac_present_h2l_intr, ac_present_l2h_intr;
+  logic ec_rst_l_h2l_intr, ec_rst_l_l2h_intr;
+
+  //synchronize between cfg(24MHz) and always-on(200KHz)
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_pwrb_in_h2l (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_intr_ctl_i.pwrb_in_h2l.q),
+    .q_o(cfg_pwrb_in_h2l)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key0_in_h2l (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_intr_ctl_i.key0_in_h2l.q),
+    .q_o(cfg_key0_in_h2l)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key1_in_h2l (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_intr_ctl_i.key1_in_h2l.q),
+    .q_o(cfg_key1_in_h2l)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key2_in_h2l (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_intr_ctl_i.key2_in_h2l.q),
+    .q_o(cfg_key2_in_h2l)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_ac_present_h2l (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_intr_ctl_i.ac_present_h2l.q),
+    .q_o(cfg_ac_present_h2l)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_ec_rst_l_h2l (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_intr_ctl_i.ec_rst_l_h2l.q),
+    .q_o(cfg_ec_rst_l_h2l)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_pwrb_in_l2h (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_intr_ctl_i.pwrb_in_l2h.q),
+    .q_o(cfg_pwrb_in_l2h)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key0_in_l2h (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_intr_ctl_i.key0_in_l2h.q),
+    .q_o(cfg_key0_in_l2h)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key1_in_l2h (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_intr_ctl_i.key1_in_l2h.q),
+    .q_o(cfg_key1_in_l2h)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key2_in_l2h (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_intr_ctl_i.key2_in_l2h.q),
+    .q_o(cfg_key2_in_l2h)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_ac_present_l2h (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_intr_ctl_i.ac_present_l2h.q),
+    .q_o(cfg_ac_present_l2h)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_ec_rst_l_l2h (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key_intr_ctl_i.ec_rst_l_l2h.q),
+    .q_o(cfg_ec_rst_l_l2h)
+  );
+
+  prim_fifo_async #(
+    .Width(16),
+    .Depth(2)
+  ) i_cfg_key_intr_timer (
+    .clk_wr_i  (clk_i),
+    .rst_wr_ni (rst_ni),
+    .wvalid_i  (key_intr_debounce_ctl_i.qe),
+    .wready_o  (),
+    .wdata_i   (key_intr_debounce_ctl_i.q),
+    .wdepth_o  (),
+
+    .clk_rd_i  (clk_aon_i),
+    .rst_rd_ni (rst_slow_ni),
+    .rvalid_o  (load_key_intr_timer),
+    .rready_i  (1'b1),
+    .rdata_o   (cfg_key_intr_timer_d),
+    .rdepth_o  ()
+  );
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_cfg_key_intr_timer_reg
+    if (!rst_slow_ni) begin
+      cfg_key_intr_timer    <= '0;
+    end else if (load_key_intr_timer) begin
+      cfg_key_intr_timer    <= cfg_key_intr_timer_d;
+    end
+  end
+
+  //synchronize between GPIO and always-on(200KHz)
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_pwrb_int_i (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pwrb_int),
+    .q_o(pwrb_int_i)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_key0_int_i (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key0_int),
+    .q_o(key0_int_i)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_key1_int_i (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key1_int),
+    .q_o(key1_int_i)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_key2_int_i (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(key2_int),
+    .q_o(key2_int_i)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_ac_present_int_i (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(ac_present_int),
+    .q_o(ac_present_int_i)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_ec_rst_l_int_i (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(cio_ec_rst_l_i),
+    .q_o(ec_rst_l_int_i)
+  );
+
+  //Instantiate the key state machine
+  rbox_keyfsm # (
+    .TIMERBIT(16)
+  ) i_pwrbintr_fsm (
+    .clk_aon_i(clk_aon_i),
+    .rst_slow_ni(rst_slow_ni),
+    .trigger_i(pwrb_int_i),
+    .cfg_timer_i(cfg_key_intr_timer),
+    .cfg_l2h_en_i(cfg_pwrb_in_l2h),
+    .cfg_h2l_en_i(cfg_pwrb_in_h2l),
+    .timer_l2h_cond_met(pwrb_intr_l2h_det),
+    .timer_h2l_cond_met(pwrb_intr_h2l_det)
+  );
+
+  rbox_keyfsm # (
+    .TIMERBIT(16)
+  ) i_key0intr_fsm (
+    .clk_aon_i(clk_aon_i),
+    .rst_slow_ni(rst_slow_ni),
+    .trigger_i(key0_int_i),
+    .cfg_timer_i(cfg_key_intr_timer),
+    .cfg_l2h_en_i(cfg_key0_in_l2h),
+    .cfg_h2l_en_i(cfg_key0_in_h2l),
+    .timer_l2h_cond_met(key0_intr_l2h_det),
+    .timer_h2l_cond_met(key0_intr_h2l_det)
+  );
+
+  rbox_keyfsm # (
+    .TIMERBIT(16)
+  ) i_key1intr_fsm (
+    .clk_aon_i(clk_aon_i),
+    .rst_slow_ni(rst_slow_ni),
+    .trigger_i(key1_int_i),
+    .cfg_timer_i(cfg_key_intr_timer),
+    .cfg_l2h_en_i(cfg_key1_in_l2h),
+    .cfg_h2l_en_i(cfg_key1_in_h2l),
+    .timer_l2h_cond_met(key1_intr_l2h_det),
+    .timer_h2l_cond_met(key1_intr_h2l_det)
+  );
+
+  rbox_keyfsm # (
+    .TIMERBIT(16)
+  ) i_key2intr_fsm (
+    .clk_aon_i(clk_aon_i),
+    .rst_slow_ni(rst_slow_ni),
+    .trigger_i(key2_int_i),
+    .cfg_timer_i(cfg_key_intr_timer),
+    .cfg_l2h_en_i(cfg_key2_in_l2h),
+    .cfg_h2l_en_i(cfg_key2_in_h2l),
+    .timer_l2h_cond_met(key2_intr_l2h_det),
+    .timer_h2l_cond_met(key2_intr_h2l_det)
+  );
+
+  rbox_keyfsm # (
+    .TIMERBIT(16)
+  ) i_ac_presentintr_fsm (
+    .clk_aon_i(clk_aon_i),
+    .rst_slow_ni(rst_slow_ni),
+    .trigger_i(ac_present_int_i),
+    .cfg_timer_i(cfg_key_intr_timer),
+    .cfg_l2h_en_i(cfg_ac_present_l2h),
+    .cfg_h2l_en_i(cfg_ac_present_h2l),
+    .timer_l2h_cond_met(ac_present_intr_l2h_det),
+    .timer_h2l_cond_met(ac_present_intr_h2l_det)
+  );
+
+  rbox_keyfsm # (
+    .TIMERBIT(16)
+  ) i_ec_rst_lintr_fsm (
+    .clk_aon_i(clk_aon_i),
+    .rst_slow_ni(rst_slow_ni),
+    .trigger_i(ec_rst_l_int_i),
+    .cfg_timer_i(cfg_key_intr_timer),
+    .cfg_l2h_en_i(cfg_ec_rst_l_l2h),
+    .cfg_h2l_en_i(cfg_ec_rst_l_h2l),
+    .timer_l2h_cond_met(ec_rst_l_intr_l2h_det),
+    .timer_h2l_cond_met(ec_rst_l_intr_h2l_det)
+  );
+
+
+  //delay the level signal to generate a pulse
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_pwrb_intr_h2l_det
+    if (!rst_slow_ni) begin
+      pwrb_intr_h2l_det_q    <= 1'b0;
+    end else begin
+      pwrb_intr_h2l_det_q    <= pwrb_intr_h2l_det;
+    end
+  end
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_pwrb_intr_l2h_det
+    if (!rst_slow_ni) begin
+      pwrb_intr_l2h_det_q    <= 1'b0;
+    end else begin
+      pwrb_intr_l2h_det_q    <= pwrb_intr_l2h_det;
+    end
+  end
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_key0_intr_h2l_det
+    if (!rst_slow_ni) begin
+      key0_intr_h2l_det_q    <= 1'b0;
+    end else begin
+      key0_intr_h2l_det_q    <= key0_intr_h2l_det;
+    end
+  end
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_key0_intr_l2h_det
+    if (!rst_slow_ni) begin
+      key0_intr_l2h_det_q    <= 1'b0;
+    end else begin
+      key0_intr_l2h_det_q    <= key0_intr_l2h_det;
+    end
+  end
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_key1_intr_h2l_det
+    if (!rst_slow_ni) begin
+      key1_intr_h2l_det_q    <= 1'b0;
+    end else begin
+      key1_intr_h2l_det_q    <= key1_intr_h2l_det;
+    end
+  end
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_key1_intr_l2h_det
+    if (!rst_slow_ni) begin
+      key1_intr_l2h_det_q    <= 1'b0;
+    end else begin
+      key1_intr_l2h_det_q    <= key1_intr_l2h_det;
+    end
+  end
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_key2_intr_h2l_det
+    if (!rst_slow_ni) begin
+      key2_intr_h2l_det_q    <= 1'b0;
+    end else begin
+      key2_intr_h2l_det_q    <= key2_intr_h2l_det;
+    end
+  end
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_key2_intr_l2h_det
+    if (!rst_slow_ni) begin
+      key2_intr_l2h_det_q    <= 1'b0;
+    end else begin
+      key2_intr_l2h_det_q    <= key2_intr_l2h_det;
+    end
+  end
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_ac_present_intr_h2l_det
+    if (!rst_slow_ni) begin
+      ac_present_intr_h2l_det_q    <= 1'b0;
+    end else begin
+      ac_present_intr_h2l_det_q    <= ac_present_intr_h2l_det;
+    end
+  end
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_ac_present_intr_l2h_det
+    if (!rst_slow_ni) begin
+      ac_present_intr_l2h_det_q    <= 1'b0;
+    end else begin
+      ac_present_intr_l2h_det_q    <= ac_present_intr_l2h_det;
+    end
+  end
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_ec_rst_l_intr_h2l_det
+    if (!rst_slow_ni) begin
+      ec_rst_l_intr_h2l_det_q    <= 1'b0;
+    end else begin
+      ec_rst_l_intr_h2l_det_q    <= ec_rst_l_intr_h2l_det;
+    end
+  end
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_ec_rst_l_intr_l2h_det
+    if (!rst_slow_ni) begin
+      ec_rst_l_intr_l2h_det_q    <= 1'b0;
+    end else begin
+      ec_rst_l_intr_l2h_det_q    <= ec_rst_l_intr_l2h_det;
+    end
+  end
+
+  //generate a pulse for interrupt status CSR
+  assign pwrb_intr_l2h_pulse = (pwrb_intr_l2h_det_q == 1'b0) && (pwrb_intr_l2h_det == 1'b1);
+  assign pwrb_intr_h2l_pulse = (pwrb_intr_h2l_det_q == 1'b1) && (pwrb_intr_h2l_det == 1'b0);
+  assign key0_intr_l2h_pulse = (key0_intr_l2h_det_q == 1'b0) && (key0_intr_l2h_det == 1'b1);
+  assign key0_intr_h2l_pulse = (key0_intr_h2l_det_q == 1'b1) && (key0_intr_h2l_det == 1'b0);
+  assign key1_intr_l2h_pulse = (key1_intr_l2h_det_q == 1'b0) && (key1_intr_l2h_det == 1'b1);
+  assign key1_intr_h2l_pulse = (key1_intr_h2l_det_q == 1'b1) && (key1_intr_h2l_det == 1'b0);
+  assign key2_intr_l2h_pulse = (key2_intr_l2h_det_q == 1'b0) && (key2_intr_l2h_det == 1'b1);
+  assign key2_intr_h2l_pulse = (key2_intr_h2l_det_q == 1'b1) && (key2_intr_h2l_det == 1'b0);
+  assign ac_present_intr_l2h_pulse = (ac_present_intr_l2h_det_q == 1'b0) &&
+          (ac_present_intr_l2h_det == 1'b1);
+  assign ac_present_intr_h2l_pulse = (ac_present_intr_h2l_det_q == 1'b1) &&
+          (ac_present_intr_h2l_det == 1'b0);
+  assign ec_rst_l_intr_l2h_pulse = (ec_rst_l_intr_l2h_det_q == 1'b0) &&
+          (ec_rst_l_intr_l2h_det == 1'b1);
+  assign ec_rst_l_intr_h2l_pulse = (ec_rst_l_intr_h2l_det_q == 1'b1) &&
+          (ec_rst_l_intr_h2l_det == 1'b0);
+
+  //Synchronize from 200KHz always-onclock to 24MHz cfg clock
+  prim_pulse_sync i_pwrb_h2l (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (pwrb_intr_h2l_pulse),
+    .dst_pulse_o (pwrb_h2l_intr)
+  );
+
+  assign key_intr_status_o.pwrb_h2l.de = pwrb_h2l_intr;
+
+  prim_pulse_sync i_pwrb_l2h (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (pwrb_intr_l2h_pulse),
+    .dst_pulse_o (pwrb_l2h_intr)
+  );
+
+  assign key_intr_status_o.pwrb_l2h.de = pwrb_l2h_intr;
+
+  prim_pulse_sync i_key0_in_h2l (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (key0_intr_h2l_pulse),
+    .dst_pulse_o (key0_in_h2l_intr)
+  );
+
+  assign key_intr_status_o.key0_in_h2l.de = key0_in_h2l_intr;
+
+  prim_pulse_sync i_key0_in_l2h (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (key0_intr_l2h_pulse),
+    .dst_pulse_o (key0_in_l2h_intr)
+  );
+
+  assign key_intr_status_o.key0_in_l2h.de = key0_in_l2h_intr;
+
+  prim_pulse_sync i_key1_in_h2l (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (key1_intr_h2l_pulse),
+    .dst_pulse_o (key1_in_h2l_intr)
+  );
+
+  assign key_intr_status_o.key1_in_h2l.de = key1_in_h2l_intr;
+
+  prim_pulse_sync i_key1_in_l2h (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (key1_intr_l2h_pulse),
+    .dst_pulse_o (key1_in_l2h_intr)
+  );
+
+  assign key_intr_status_o.key1_in_l2h.de = key1_in_l2h_intr;
+
+  prim_pulse_sync i_key2_in_h2l (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (key2_intr_h2l_pulse),
+    .dst_pulse_o (key2_in_h2l_intr)
+  );
+
+  assign key_intr_status_o.key2_in_h2l.de = key2_in_h2l_intr;
+
+  prim_pulse_sync i_key2_in_l2h (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (key2_intr_l2h_pulse),
+    .dst_pulse_o (key2_in_l2h_intr)
+  );
+
+  assign key_intr_status_o.key2_in_l2h.de = key2_in_l2h_intr;
+
+  prim_pulse_sync i_ac_present_h2l (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (ac_present_intr_h2l_pulse),
+    .dst_pulse_o (ac_present_h2l_intr)
+  );
+
+  assign key_intr_status_o.ac_present_h2l.de = ac_present_h2l_intr;
+
+  prim_pulse_sync i_ac_present_l2h (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (ac_present_intr_l2h_pulse),
+    .dst_pulse_o (ac_present_l2h_intr)
+  );
+
+  assign key_intr_status_o.ac_present_l2h.de = ac_present_l2h_intr;
+
+  prim_pulse_sync i_ec_rst_l_h2l (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (ec_rst_l_intr_h2l_pulse),
+    .dst_pulse_o (ec_rst_l_h2l_intr)
+  );
+
+  assign key_intr_status_o.ec_rst_l_h2l.de = ec_rst_l_h2l_intr;
+
+  prim_pulse_sync i_ec_rst_l_l2h (
+    .clk_src_i   (clk_aon_i),
+    .clk_dst_i   (clk_i),
+    .rst_src_ni  (rst_slow_ni),
+    .rst_dst_ni  (rst_ni),
+    .src_pulse_i (ec_rst_l_intr_l2h_pulse),
+    .dst_pulse_o (ec_rst_l_l2h_intr)
+  );
+
+  assign key_intr_status_o.ec_rst_l_l2h.de = ec_rst_l_l2h_intr;
+
+  assign rbox_key_intr = pwrb_h2l_intr | pwrb_l2h_intr |
+   key0_in_h2l_intr | key0_in_l2h_intr |
+   key1_in_h2l_intr | key1_in_l2h_intr |
+   key2_in_h2l_intr | key2_in_l2h_intr |
+   ac_present_h2l_intr | ac_present_l2h_intr |
+   ec_rst_l_h2l_intr | ec_rst_l_l2h_intr;
+
+  //To write into interrupt status register
+  assign key_intr_status_o.pwrb_h2l.d = 1'b1;
+  assign key_intr_status_o.pwrb_l2h.d = 1'b1;
+  assign key_intr_status_o.key0_in_h2l.d = 1'b1;
+  assign key_intr_status_o.key0_in_l2h.d = 1'b1;
+  assign key_intr_status_o.key1_in_h2l.d = 1'b1;
+  assign key_intr_status_o.key1_in_l2h.d = 1'b1;
+  assign key_intr_status_o.key2_in_h2l.d = 1'b1;
+  assign key_intr_status_o.key2_in_l2h.d = 1'b1;
+  assign key_intr_status_o.ac_present_h2l.d = 1'b1;
+  assign key_intr_status_o.ac_present_l2h.d = 1'b1;
+  assign key_intr_status_o.ec_rst_l_h2l.d = 1'b1;
+  assign key_intr_status_o.ec_rst_l_l2h.d = 1'b1;
+
+endmodule
diff --git a/hw/ip/rbox/rtl/rbox_pin.sv b/hw/ip/rbox/rtl/rbox_pin.sv
new file mode 100644
index 0000000..1c660e6
--- /dev/null
+++ b/hw/ip/rbox/rtl/rbox_pin.sv
@@ -0,0 +1,408 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description: RBOX pin visibility and override Module
+//
+
+module rbox_pin import rbox_reg_pkg::*; (
+  input  clk_aon_i,
+  input  rst_slow_ni,
+  input  clk_i,
+  input  rst_ni,
+
+  input  cio_pwrb_in_i,
+  input  cio_key0_in_i,
+  input  cio_key1_in_i,
+  input  cio_key2_in_i,
+  input  cio_ac_present_i,
+  input  cio_ec_rst_l_i,
+
+  input  pwrb_out_hw,
+  input  key0_out_hw,
+  input  key1_out_hw,
+  input  key2_out_hw,
+  input  bat_disable_hw,
+  input  ec_rst_l_hw,
+
+  input  rbox_reg2hw_pin_allowed_ctl_reg_t pin_allowed_ctl_i,
+  input  rbox_reg2hw_pin_out_ctl_reg_t pin_out_ctl_i,
+  input  rbox_reg2hw_pin_out_value_reg_t pin_out_value_i,
+
+  output rbox_hw2reg_pin_in_value_reg_t pin_in_value_o,
+
+  output pwrb_out_int,
+  output key0_out_int,
+  output key1_out_int,
+  output key2_out_int,
+  output bat_disable_int,
+  output cio_ec_rst_l_o
+
+);
+
+  logic cfg_ac_present_i_pin;
+  logic cfg_ec_rst_l_i_pin;
+  logic cfg_pwrb_in_i_pin;
+  logic cfg_key0_in_i_pin;
+  logic cfg_key1_in_i_pin;
+  logic cfg_key2_in_i_pin;
+
+  logic cfg_bat_disable_0_allow;
+  logic cfg_ec_rst_l_0_allow;
+  logic cfg_pwrb_out_0_allow;
+  logic cfg_key0_out_0_allow;
+  logic cfg_key1_out_0_allow;
+  logic cfg_key2_out_0_allow;
+  logic cfg_bat_disable_1_allow;
+  logic cfg_ec_rst_l_1_allow;
+  logic cfg_pwrb_out_1_allow;
+  logic cfg_key0_out_1_allow;
+  logic cfg_key1_out_1_allow;
+  logic cfg_key2_out_1_allow;
+
+  logic cfg_bat_disable_ov;
+  logic cfg_ec_rst_l_ov;
+  logic cfg_pwrb_out_ov;
+  logic cfg_key0_out_ov;
+  logic cfg_key1_out_ov;
+  logic cfg_key2_out_ov;
+
+  logic cfg_bat_disable_q;
+  logic cfg_ec_rst_l_q;
+  logic cfg_pwrb_out_q;
+  logic cfg_key0_out_q;
+  logic cfg_key1_out_q;
+  logic cfg_key2_out_q;
+
+  //Synchronize between GPIO and cfg(24MHz)
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_ac_present_i_pin (
+    .clk_i(clk_i),
+    .rst_ni(rst_ni),
+    .d_i(cio_ac_present_i),
+    .q_o(cfg_ac_present_i_pin)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_ec_rst_l_i_pin (
+    .clk_i(clk_i),
+    .rst_ni(rst_ni),
+    .d_i(cio_ec_rst_l_i),
+    .q_o(cfg_ec_rst_l_i_pin)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_pwrb_in_i_pin (
+    .clk_i(clk_i),
+    .rst_ni(rst_ni),
+    .d_i(cio_pwrb_in_i),
+    .q_o(cfg_pwrb_in_i_pin)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key0_in_i_pin (
+    .clk_i(clk_i),
+    .rst_ni(rst_ni),
+    .d_i(cio_key0_in_i),
+    .q_o(cfg_key0_in_i_pin)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key1_in_i_pin (
+    .clk_i(clk_i),
+    .rst_ni(rst_ni),
+    .d_i(cio_key1_in_i),
+    .q_o(cfg_key1_in_i_pin)
+  );
+
+  prim_flop_2sync # (
+    .Width(1)
+  ) i_cfg_key2_in_i_pin (
+    .clk_i(clk_i),
+    .rst_ni(rst_ni),
+    .d_i(cio_key2_in_i),
+    .q_o(cfg_key2_in_i_pin)
+  );
+
+  //Use the raw input(not inverted)
+  assign pin_in_value_o.ac_present.d = cfg_ac_present_i_pin;
+  assign pin_in_value_o.ec_rst_l.d = cfg_ec_rst_l_i_pin;
+  assign pin_in_value_o.pwrb_in.d = cfg_pwrb_in_i_pin;
+  assign pin_in_value_o.key0_in.d = cfg_key0_in_i_pin;
+  assign pin_in_value_o.key1_in.d = cfg_key1_in_i_pin;
+  assign pin_in_value_o.key2_in.d = cfg_key2_in_i_pin;
+
+  assign pin_in_value_o.ac_present.de = 1'b1;
+  assign pin_in_value_o.ec_rst_l.de = 1'b1;
+  assign pin_in_value_o.pwrb_in.de = 1'b1;
+  assign pin_in_value_o.key0_in.de = 1'b1;
+  assign pin_in_value_o.key1_in.de = 1'b1;
+  assign pin_in_value_o.key2_in.de = 1'b1;
+
+  //synchronize between cfg(24MHz) and always-on(200KHz)
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_bat_disable_0_allow (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_allowed_ctl_i.bat_disable_0.q),
+    .q_o(cfg_bat_disable_0_allow)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue(1'b1)//ec_rst_l_0_allow is enabled by default
+  ) i_cfg_ec_rst_l_0_allow (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_allowed_ctl_i.ec_rst_l_0.q),
+    .q_o(cfg_ec_rst_l_0_allow)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_pwrb_out_0_allow (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_allowed_ctl_i.pwrb_out_0.q),
+    .q_o(cfg_pwrb_out_0_allow)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_key0_out_0_allow (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_allowed_ctl_i.key0_out_0.q),
+    .q_o(cfg_key0_out_0_allow)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_key1_out_0_allow (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_allowed_ctl_i.key1_out_0.q),
+    .q_o(cfg_key1_out_0_allow)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_key2_out_0_allow (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_allowed_ctl_i.key2_out_0.q),
+    .q_o(cfg_key2_out_0_allow)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_bat_disable_1_allow (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_allowed_ctl_i.bat_disable_1.q),
+    .q_o(cfg_bat_disable_1_allow)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_ec_rst_l_1_allow (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_allowed_ctl_i.ec_rst_l_1.q),
+    .q_o(cfg_ec_rst_l_1_allow)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_pwrb_out_1_allow (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_allowed_ctl_i.pwrb_out_1.q),
+    .q_o(cfg_pwrb_out_1_allow)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_key0_out_1_allow (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_allowed_ctl_i.key0_out_1.q),
+    .q_o(cfg_key0_out_1_allow)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_key1_out_1_allow (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_allowed_ctl_i.key1_out_1.q),
+    .q_o(cfg_key1_out_1_allow)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_key2_out_1_allow (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_allowed_ctl_i.key2_out_1.q),
+    .q_o(cfg_key2_out_1_allow)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_bat_disable_ov (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_out_ctl_i.bat_disable.q),
+    .q_o(cfg_bat_disable_ov)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue(1'b1)//ec_rst_l override is enabled by default
+  ) i_cfg_ec_rst_l_ov (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_out_ctl_i.ec_rst_l.q),
+    .q_o(cfg_ec_rst_l_ov)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_pwrb_out_ov (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_out_ctl_i.pwrb_out.q),
+    .q_o(cfg_pwrb_out_ov)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_key0_out_ov (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_out_ctl_i.key0_out.q),
+    .q_o(cfg_key0_out_ov)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_key1_out_ov (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_out_ctl_i.key1_out.q),
+    .q_o(cfg_key1_out_ov)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_key2_out_ov (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_out_ctl_i.key2_out.q),
+    .q_o(cfg_key2_out_ov)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_bat_disable_q (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_out_value_i.bat_disable.q),
+    .q_o(cfg_bat_disable_q)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_ec_rst_l_q (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_out_value_i.ec_rst_l.q),
+    .q_o(cfg_ec_rst_l_q)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_pwrb_out_q (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_out_value_i.pwrb_out.q),
+    .q_o(cfg_pwrb_out_q)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_key0_out_q (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_out_value_i.key0_out.q),
+    .q_o(cfg_key0_out_q)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_key1_out_q (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_out_value_i.key1_out.q),
+    .q_o(cfg_key1_out_q)
+  );
+
+  prim_flop_2sync # (
+    .Width(1),
+    .ResetValue('0)
+  ) i_cfg_key2_out_q (
+    .clk_i(clk_aon_i),
+    .rst_ni(rst_slow_ni),
+    .d_i(pin_out_value_i.key2_out.q),
+    .q_o(cfg_key2_out_q)
+  );
+
+  assign pwrb_out_int = (cfg_pwrb_out_ov && cfg_pwrb_out_0_allow && !cfg_pwrb_out_q) ? 1'b0 :
+               ((cfg_pwrb_out_ov && cfg_pwrb_out_1_allow && cfg_pwrb_out_q) ? 1'b1 : pwrb_out_hw);
+
+  assign key0_out_int = (cfg_key0_out_ov && cfg_key0_out_0_allow && !cfg_key0_out_q) ? 1'b0 :
+               ((cfg_key0_out_ov && cfg_key0_out_1_allow && cfg_key0_out_q) ? 1'b1 : key0_out_hw);
+
+  assign key1_out_int = (cfg_key1_out_ov && cfg_key1_out_0_allow && !cfg_key1_out_q) ? 1'b0 :
+               ((cfg_key1_out_ov && cfg_key1_out_1_allow && cfg_key1_out_q) ? 1'b1 : key1_out_hw);
+
+  assign key2_out_int = (cfg_key2_out_ov && cfg_key2_out_0_allow && !cfg_key2_out_q) ? 1'b0 :
+               ((cfg_key2_out_ov && cfg_key2_out_1_allow && cfg_key2_out_q) ? 1'b1 : key2_out_hw);
+
+  assign bat_disable_int =
+          (cfg_bat_disable_ov && cfg_bat_disable_0_allow && !cfg_bat_disable_q) ? 1'b0 :
+          ((cfg_bat_disable_ov && cfg_bat_disable_1_allow && cfg_bat_disable_q) ? 1'b1 :
+          bat_disable_hw);
+
+  assign cio_ec_rst_l_o = (cfg_ec_rst_l_ov && cfg_ec_rst_l_0_allow && !cfg_ec_rst_l_q) ? 1'b0 :
+               ((cfg_ec_rst_l_ov && cfg_ec_rst_l_1_allow && cfg_ec_rst_l_q) ? 1'b1 : ec_rst_l_hw);
+
+endmodule
diff --git a/hw/ip/rbox/rtl/rbox_timerfsm.sv b/hw/ip/rbox/rtl/rbox_timerfsm.sv
new file mode 100644
index 0000000..91ebf53
--- /dev/null
+++ b/hw/ip/rbox/rtl/rbox_timerfsm.sv
@@ -0,0 +1,147 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description RBOX timer-based FSM module
+
+module rbox_timerfsm #(
+  parameter int unsigned TIMERBIT = 16
+  ) (
+  input                clk_aon_i,
+  input                rst_slow_ni,
+  input                trigger_i,
+  input [TIMERBIT-1:0] cfg_timer_i,
+  input                cfg_l2h_en_i,
+  input                cfg_h2l_en_i,
+  output logic         timer_l2h_cond_met,
+  output logic         timer_h2l_cond_met
+
+);
+
+  logic trigger_q;
+  logic trigger_h2l, trigger_l2h, trigger_h2h, trigger_l2l;
+  logic trigger_tgl, trigger_sty;
+
+  logic [TIMERBIT-1:0] timer_cnt_d, timer_cnt_q;
+  logic timer_cnt_clr, timer_cnt_en;
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_trigger_reg
+    if (!rst_slow_ni) begin
+      trigger_q    <= 1'b0;
+    end else begin
+      trigger_q    <= trigger_i;
+    end
+  end
+
+  assign trigger_h2l = (trigger_q == 1'b1) && (trigger_i == 1'b0);
+  assign trigger_l2h = (trigger_q == 1'b0) && (trigger_i == 1'b1);
+  assign trigger_h2h = (trigger_q == 1'b1) && (trigger_i == 1'b1);
+  assign trigger_l2l = (trigger_q == 1'b0) && (trigger_i == 1'b0);
+  assign trigger_tgl = trigger_q != trigger_i;
+  assign trigger_sty = trigger_q == trigger_i;
+
+  //three-state FSM
+  //IDLE->WAITL2H->DONEL2H or IDLE->WAITH2L->DONEH2L
+  //The input signals can be inverted. Hence, both paths
+  //FSM will detect a L2H or H2L transition to enter the wait state
+  //debounce timer defines the time to wait for input to stablize
+  //FSM will check the input after the debounce period
+  typedef enum logic [2:0] {
+                            IDLE = 3'h0,
+                            WAITL2H = 3'h1,
+                            WAITH2L = 3'h2,
+                            DONEL2H = 3'h3,
+                            DONEH2L = 3'h4
+                            } timer_state_e;
+
+  timer_state_e timer_state_q, timer_state_d;
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_timer_state_reg
+    if (!rst_slow_ni) begin
+      timer_state_q    <= IDLE;
+    end else begin
+      timer_state_q    <= timer_state_d;
+    end
+  end
+
+  assign timer_cnt_d = (timer_cnt_en) ? timer_cnt_q + 1'b1 : timer_cnt_q;
+
+  always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_timer_cnt_reg
+    if (!rst_slow_ni) begin
+      timer_cnt_q    <= '0;
+    end
+    else if (timer_cnt_clr) begin
+      timer_cnt_q <= '0;
+    end else begin
+      timer_cnt_q <= timer_cnt_d;
+    end
+  end
+
+  always_comb begin: timer_fsm
+    timer_state_d = timer_state_q;
+    //outputs
+    timer_l2h_cond_met = 1'b0;
+    timer_h2l_cond_met = 1'b0;
+    timer_cnt_clr = 1'b0;
+    timer_cnt_en = 1'b0;
+
+    unique case (timer_state_q)
+      IDLE: begin
+        if (cfg_l2h_en_i &&  trigger_l2h) begin
+          timer_state_d = WAITL2H;
+        end
+        else if (cfg_h2l_en_i &&  trigger_h2l) begin
+          timer_state_d = WAITH2L;
+        end
+      end
+
+      WAITL2H: begin
+        if (timer_cnt_q != cfg_timer_i) begin
+          timer_cnt_en = 1'b1;
+        end
+        else if (!trigger_h2h && (timer_cnt_q == cfg_timer_i)) begin
+          timer_state_d = IDLE;
+          timer_cnt_clr = 1'b1;
+        end
+        else if (trigger_h2h && (timer_cnt_q == cfg_timer_i)) begin
+          timer_state_d = DONEL2H;
+          timer_cnt_clr = 1'b1;
+        end
+      end
+
+      DONEL2H: begin
+        if (trigger_h2h) begin
+          timer_l2h_cond_met = 1'b1;
+        end
+        else if (trigger_h2l) begin
+          timer_state_d = IDLE;
+        end
+      end
+
+      WAITH2L: begin
+        if (timer_cnt_q != cfg_timer_i) begin
+          timer_cnt_en = 1'b1;
+        end
+        else if (!trigger_l2l && (timer_cnt_q == cfg_timer_i)) begin
+          timer_state_d = IDLE;
+          timer_cnt_clr = 1'b1;
+        end
+        else if (trigger_l2l && (timer_cnt_q == cfg_timer_i)) begin
+          timer_state_d = DONEH2L;
+          timer_cnt_clr = 1'b1;
+        end
+      end
+
+      DONEH2L: begin
+        if (trigger_l2l) begin
+          timer_h2l_cond_met = 1'b1;
+        end
+        else if (trigger_l2h) begin
+          timer_state_d = IDLE;
+        end
+      end
+      default: timer_state_d = IDLE;
+    endcase
+  end
+
+endmodule
diff --git a/hw/top_earlgrey/lint/top_earlgrey_lint_cfgs.hjson b/hw/top_earlgrey/lint/top_earlgrey_lint_cfgs.hjson
index 5390d81..019c380 100644
--- a/hw/top_earlgrey/lint/top_earlgrey_lint_cfgs.hjson
+++ b/hw/top_earlgrey/lint/top_earlgrey_lint_cfgs.hjson
@@ -142,6 +142,11 @@
                     }
                   ]
              },
+             {    name: rbox
+                  fusesoc_core: lowrisc:ip:rbox
+                  import_cfgs: ["{proj_root}/hw/lint/tools/dvsim/common_lint_cfg.hjson"]
+                  rel_path: "hw/ip/rbox/lint/{tool}"
+             },
              {    name: rstmgr
                   fusesoc_core: lowrisc:ip:rstmgr
                   import_cfgs: ["{proj_root}/hw/lint/tools/dvsim/common_lint_cfg.hjson"],