blob: e2aae36b370056c75e032b0bf2b083f4bd48861e [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Description: sysrst_ctrl key-triggered interrupt Module
//
module sysrst_ctrl_keyintr import sysrst_ctrl_reg_pkg::*; (
input clk_aon_i,
input rst_aon_ni,
input clk_i,
input rst_ni,
input pwrb_int_i,
input key0_int_i,
input key1_int_i,
input key2_int_i,
input ac_present_int_i,
input cio_ec_rst_in_l_i,
input sysrst_ctrl_reg2hw_key_intr_ctl_reg_t key_intr_ctl_i,
input sysrst_ctrl_reg2hw_key_intr_debounce_ctl_reg_t key_intr_debounce_ctl_i,
output sysrst_ctrl_hw2reg_key_intr_status_reg_t key_intr_status_o,
output sysrst_ctrl_key_intr_o
);
logic pwrb_int;
logic key0_int, key1_int, key2_int;
logic ac_present_int;
logic ec_rst_l_int;
//synchronize between GPIO and always-on(200KHz)
prim_flop_2sync # (
.Width(1)
) u_pwrb_int_i (
.clk_i(clk_aon_i),
.rst_ni(rst_aon_ni),
.d_i(pwrb_int_i),
.q_o(pwrb_int)
);
prim_flop_2sync # (
.Width(1)
) u_key0_int_i (
.clk_i(clk_aon_i),
.rst_ni(rst_aon_ni),
.d_i(key0_int_i),
.q_o(key0_int)
);
prim_flop_2sync # (
.Width(1)
) u_key1_int_i (
.clk_i(clk_aon_i),
.rst_ni(rst_aon_ni),
.d_i(key1_int_i),
.q_o(key1_int)
);
prim_flop_2sync # (
.Width(1)
) u_key2_int_i (
.clk_i(clk_aon_i),
.rst_ni(rst_aon_ni),
.d_i(key2_int_i),
.q_o(key2_int)
);
prim_flop_2sync # (
.Width(1)
) u_ac_present_int_i (
.clk_i(clk_aon_i),
.rst_ni(rst_aon_ni),
.d_i(ac_present_int_i),
.q_o(ac_present_int)
);
prim_flop_2sync # (
.Width(1)
) u_ec_rst_l_int (
.clk_i(clk_aon_i),
.rst_ni(rst_aon_ni),
.d_i(cio_ec_rst_in_l_i),
.q_o(ec_rst_l_int)
);
localparam int TimerWidth = 16;
localparam int NumKeyIntr = 6;
logic [NumKeyIntr-1:0] triggers, l2h_en, h2l_en;
assign triggers = {pwrb_int,
key0_int,
key1_int,
key2_int,
ac_present_int,
ec_rst_l_int};
assign l2h_en = {key_intr_ctl_i.pwrb_in_l2h.q,
key_intr_ctl_i.key0_in_l2h.q,
key_intr_ctl_i.key1_in_l2h.q,
key_intr_ctl_i.key2_in_l2h.q,
key_intr_ctl_i.ac_present_l2h.q,
key_intr_ctl_i.ec_rst_l_l2h.q};
assign h2l_en = {key_intr_ctl_i.pwrb_in_h2l.q,
key_intr_ctl_i.key0_in_h2l.q,
key_intr_ctl_i.key1_in_h2l.q,
key_intr_ctl_i.key2_in_h2l.q,
key_intr_ctl_i.ac_present_h2l.q,
key_intr_ctl_i.ec_rst_l_h2l.q};
logic [NumKeyIntr-1:0] l2h_met_pulse_synced, h2l_met_pulse_synced;
for (genvar k = 0; k < NumKeyIntr; k ++) begin : gen_keyfsm
// Instantiate the key state machine
logic l2h_met_d, h2l_met_d;
sysrst_ctrl_keyfsm # (
.TimerWidth(TimerWidth)
) u_pwrbintr_fsm (
.clk_aon_i,
.rst_aon_ni,
.trigger_i(triggers[k]),
.cfg_timer_i(key_intr_debounce_ctl_i.q),
.cfg_l2h_en_i(l2h_en[k]),
.cfg_h2l_en_i(h2l_en[k]),
.timer_l2h_cond_met(l2h_met_d),
.timer_h2l_cond_met(h2l_met_d)
);
// generate a pulses for interrupt status CSR
logic l2h_met_q, h2l_met_q;
always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin : p_pulse_reg
if (!rst_aon_ni) begin
l2h_met_q <= '0;
h2l_met_q <= '0;
end else begin
l2h_met_q <= l2h_met_d;
h2l_met_q <= h2l_met_d;
end
end
logic l2h_met_pulse, h2l_met_pulse;
assign l2h_met_pulse = l2h_met_d & ~l2h_met_q;
assign h2l_met_pulse = ~h2l_met_d & h2l_met_q;
prim_pulse_sync u_prim_pulse_sync_l2h (
.clk_src_i (clk_aon_i),
.rst_src_ni (rst_aon_ni),
.src_pulse_i(l2h_met_pulse),
.clk_dst_i (clk_i),
.rst_dst_ni (rst_ni),
.dst_pulse_o(l2h_met_pulse_synced[k])
);
prim_pulse_sync u_prim_pulse_sync_h2l (
.clk_src_i (clk_aon_i),
.rst_src_ni (rst_aon_ni),
.src_pulse_i(h2l_met_pulse),
.clk_dst_i (clk_i),
.rst_dst_ni (rst_ni),
.dst_pulse_o(h2l_met_pulse_synced[k])
);
end
// Assign to CSRs
assign {key_intr_status_o.pwrb_l2h.de,
key_intr_status_o.key0_in_l2h.de,
key_intr_status_o.key1_in_l2h.de,
key_intr_status_o.key2_in_l2h.de,
key_intr_status_o.ac_present_l2h.de,
key_intr_status_o.ec_rst_l_l2h.de} = l2h_met_pulse_synced;
assign {key_intr_status_o.pwrb_h2l.de,
key_intr_status_o.key0_in_h2l.de,
key_intr_status_o.key1_in_h2l.de,
key_intr_status_o.key2_in_h2l.de,
key_intr_status_o.ac_present_h2l.de,
key_intr_status_o.ec_rst_l_h2l.de} = h2l_met_pulse_synced;
// Send out aggregated interrupt pulse
assign sysrst_ctrl_key_intr_o = |l2h_met_pulse_synced |
|h2l_met_pulse_synced;
// 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