| // Copyright lowRISC contributors. | |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. | |
| // SPDX-License-Identifier: Apache-2.0 | |
| // | |
| // Description: sysrst_ctrl combo Module | |
| // | |
| module sysrst_ctrl_combo import sysrst_ctrl_reg_pkg::*; ( | |
| input clk_aon_i, | |
| input rst_aon_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_in_l_i, | |
| input sysrst_ctrl_reg2hw_ec_rst_ctl_reg_t ec_rst_ctl_i, | |
| input sysrst_ctrl_reg2hw_key_intr_debounce_ctl_reg_t key_intr_debounce_ctl_i, | |
| input sysrst_ctrl_reg2hw_com_sel_ctl_mreg_t [NumCombo-1:0] com_sel_ctl_i, | |
| input sysrst_ctrl_reg2hw_com_det_ctl_mreg_t [NumCombo-1:0] com_det_ctl_i, | |
| input sysrst_ctrl_reg2hw_com_out_ctl_mreg_t [NumCombo-1:0] com_out_ctl_i, | |
| output sysrst_ctrl_hw2reg_combo_intr_status_reg_t combo_intr_status_o, | |
| output sysrst_ctrl_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_aon_ni), | |
| .d_i(cio_ec_rst_in_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_aon_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_aon_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_aon_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_aon_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_aon_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_aon_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_aon_ni) begin: i_cfg_combo_timer_reg | |
| if (!rst_aon_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_aon_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_aon_ni) begin: i_cfg_debounce_timer_reg | |
| if (!rst_aon_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_aon_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_aon_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_aon_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_aon_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_aon_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_aon_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_aon_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_aon_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_aon_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 | |
| sysrst_ctrl_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 | |
| sysrst_ctrl_combofsm # ( | |
| .TIMER1BIT(16), | |
| .TIMER2BIT(32) | |
| ) i_combo_fsm ( | |
| .clk_aon_i(clk_aon_i), | |
| .rst_aon_ni(rst_aon_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 | |
| sysrst_ctrl_comboact i_combo_act ( | |
| .clk_aon_i(clk_aon_i), | |
| .rst_aon_ni(rst_aon_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_aon_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_aon_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_aon_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_aon_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 sysrst_ctrl_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 |