../src/lowrisc_ip_pinmux_component_0.1/rtl/pinmux_wkup.sv Cov: 100%

   1: // Copyright lowRISC contributors.
   2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   3: // SPDX-License-Identifier: Apache-2.0
   4: //
   5: module pinmux_wkup import pinmux_pkg::*; import pinmux_reg_pkg::*; #(
   6:   parameter Cycles = 4
   7: ) (
   8:   input                    clk_i,
   9:   input                    rst_ni,
  10:   // Always on clock / reset
  11:   input                    clk_aon_i,
  12:   input                    rst_aon_ni,
  13:   // These signals get synchronized to the
  14:   // slow AON clock within this module.
  15:   // Note that wkup_en_i is assumed to be level encoded.
  16:   input                    wkup_en_i,
  17:   input                    filter_en_i,
  18:   input wkup_mode_e        wkup_mode_i,
  19:   input [WkupCntWidth-1:0] wkup_cnt_th_i,
  20:   input                    pin_value_i,
  21:   // Signals to/from cause register.
  22:   // They are synched to/from the AON clock internally
  23:   input                    wkup_cause_valid_i,
  24:   input                    wkup_cause_data_i,
  25:   output                   wkup_cause_data_o,
  26:   // This signal is running on the AON clock
  27:   // and is held high as long as the cause register
  28:   // has not been cleared.
  29:   output logic             aon_wkup_req_o
  30: );
  31: 
  32:   ///////////////////////////
  33:   // Input Synchronization //
  34:   ///////////////////////////
  35: 
  36:   // Synchronize configuration to slow clock
  37:   wkup_mode_e aon_wkup_mode_q;
  38:   logic aon_filter_en_q;
  39:   logic aon_wkup_en_d, aon_wkup_en_q;
  40:   logic [WkupCntWidth-1:0] aon_wkup_cnt_th_q;
  41: 
  42:   prim_flop_2sync #(
  43:     .Width(1)
  44:   ) i_prim_flop_2sync_config (
  45:     .clk_i  ( clk_aon_i      ),
  46:     .rst_ni ( rst_aon_ni     ),
  47:     .d      ( wkup_en_i     ),
  48:     .q      ( aon_wkup_en_d )
  49:   );
  50: 
  51:   always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin : p_sync
  52:     if (!rst_aon_ni) begin
  53:       aon_wkup_en_q     <= 1'b0;
  54:       aon_wkup_mode_q   <= Disabled;
  55:       aon_filter_en_q   <= 1'b0;
  56:       aon_wkup_cnt_th_q <= '0;
  57:     end else begin
  58:       aon_wkup_en_q <= aon_wkup_en_d;
  59:       // latch these when going into sleep. note that these
  60:       // config signals should be stable at this point, since
  61:       // SW has configured them many cycles ago. hence no
  62:       // explicit multibit consistency check is performed.
  63:       if (aon_wkup_en_d & !aon_wkup_en_q) begin
  64:         aon_wkup_mode_q   <= wkup_mode_i;
  65:         aon_filter_en_q   <= filter_en_i;
  66:         aon_wkup_cnt_th_q <= wkup_cnt_th_i;
  67:       end
  68:     end
  69:   end
  70: 
  71:   ////////////////////////////
  72:   // Optional Signal Filter //
  73:   ////////////////////////////
  74: 
  75:   // This uses a lower value for filtering than GPIO since
  76:   // the always-on clock is slower. This can be disabled,
  77:   // in which case the signal is just combinationally bypassed.
  78:   logic aon_filter_out, aon_filter_out_d, aon_filter_out_q;
  79:   prim_filter #(
  80:     .Cycles(Cycles)
  81:   ) i_prim_filter (
  82:     .clk_i    ( clk_aon_i       ),
  83:     .rst_ni   ( rst_aon_ni      ),
  84:     .enable_i ( aon_filter_en_q ),
  85:     .filter_i ( pin_value_i     ),
  86:     .filter_o ( aon_filter_out  )
  87:   );
  88: 
  89:   // Run this through a 2 stage synchronizer to
  90:   // prevent metastability.
  91:   prim_flop_2sync #(
  92:     .Width(1)
  93:   ) i_prim_flop_2sync_filter (
  94:     .clk_i  ( clk_aon_i  ),
  95:     .rst_ni ( rst_aon_ni ),
  96:     .d      ( aon_filter_out ),
  97:     .q      ( aon_filter_out_d )
  98:   );
  99: 
 100:   //////////////////////
 101:   // Pattern Matching //
 102:   //////////////////////
 103: 
 104:   logic aon_rising, aon_falling;
 105:   assign aon_falling = ~aon_filter_out_d &  aon_filter_out_q;
 106:   assign aon_rising  =  aon_filter_out_d & ~aon_filter_out_q;
 107: 
 108:   logic aon_cnt_en, aon_cnt_eq_th;
 109:   logic [WkupCntWidth-1:0] aon_cnt_d, aon_cnt_q;
 110:   assign aon_cnt_d = (aon_cnt_eq_th) ? '0                :
 111:                      (aon_cnt_en)    ?  aon_cnt_q + 1'b1 : '0;
 112: 
 113:   assign aon_cnt_eq_th = aon_cnt_q == aon_wkup_cnt_th_q;
 114: 
 115:   logic aon_wkup_pulse;
 116:   always_comb begin : p_mode
 117:     aon_wkup_pulse = 1'b0;
 118:     aon_cnt_en     = 1'b0;
 119:     if (aon_wkup_en_q) begin
 120:       unique case (aon_wkup_mode_q)
 121:         Negedge:   aon_wkup_pulse = aon_falling;
 122:         Posedge:   aon_wkup_pulse = aon_rising;
 123:         Edge:      aon_wkup_pulse = aon_rising | aon_falling;
 124:         LowTimed: begin
 125:           aon_cnt_en = ~aon_filter_out_d;
 126:           aon_wkup_pulse = aon_cnt_eq_th;
 127:         end
 128:         HighTimed: begin
 129:           aon_cnt_en = aon_filter_out_d;
 130:           aon_wkup_pulse = aon_cnt_eq_th;
 131:         end
 132:         default: ; // also covers "Disabled"
 133:       endcase
 134:     end
 135:   end
 136: 
 137:   always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin : p_aon_pattern
 138:     if (!rst_aon_ni) begin
 139:       aon_filter_out_q <= 1'b0;
 140:       aon_cnt_q        <= '0;
 141:     end else begin
 142:       aon_filter_out_q <= aon_filter_out_d;
 143:       aon_cnt_q        <= aon_cnt_d;
 144:     end
 145:   end
 146: 
 147:   ////////////////////
 148:   // Cause register //
 149:   ////////////////////
 150: 
 151:   // to AON domain
 152:   logic aon_wkup_cause_valid, aon_wkup_cause_data;
 153:   logic aon_wkup_cause_d, aon_wkup_cause_q;
 154: 
 155:   prim_flop_2sync #(
 156:     .Width(1)
 157:   ) i_prim_flop_2sync_cause_in (
 158:     .clk_i  ( clk_aon_i  ),
 159:     .rst_ni ( rst_aon_ni ),
 160:     .d      ( wkup_cause_data_i   ),
 161:     .q      ( aon_wkup_cause_data )
 162:   );
 163: 
 164:   prim_pulse_sync i_prim_pulse_sync_cause (
 165:     .clk_src_i   ( clk_i                ),
 166:     .rst_src_ni  ( rst_ni               ),
 167:     .src_pulse_i ( wkup_cause_valid_i   ),
 168:     .clk_dst_i   ( clk_aon_i            ),
 169:     .rst_dst_ni  ( rst_aon_ni           ),
 170:     .dst_pulse_o ( aon_wkup_cause_valid )
 171:   );
 172: 
 173:   // note that aon_wkup_pulse will not be asserted when not in sleep mode
 174:   assign aon_wkup_cause_d = (aon_wkup_cause_valid) ? aon_wkup_cause_q & aon_wkup_cause_data :
 175:                                                      aon_wkup_cause_q | aon_wkup_pulse;
 176: 
 177:   // output to power manager
 178:   assign aon_wkup_req_o = aon_wkup_cause_q;
 179: 
 180:   // output to CSR
 181:   prim_flop_2sync #(
 182:     .Width(1)
 183:   ) i_prim_flop_2sync_cause_out (
 184:     .clk_i,
 185:     .rst_ni,
 186:     .d      ( aon_wkup_cause_q  ),
 187:     .q      ( wkup_cause_data_o )
 188:   );
 189: 
 190:   always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin : p_aon_cause
 191:     if (!rst_aon_ni) begin
 192:       aon_wkup_cause_q <= 1'b0;
 193:     end else begin
 194:       aon_wkup_cause_q <= aon_wkup_cause_d;
 195:     end
 196:   end
 197: 
 198: endmodule : pinmux_wkup
 199: