../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: