../src/lowrisc_ip_pwrmgr_0.1/rtl/pwrmgr.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: // Power Manager
6: //
7:
8: `include "prim_assert.sv"
9:
10: module pwrmgr import pwrmgr_pkg::*;
11: (
12: // Clocks and resets
13: input clk_slow_i,
14: input clk_i,
15: input rst_slow_ni,
16: input rst_ni,
17:
18: // Bus Interface
19: input tlul_pkg::tl_h2d_t tl_i,
20: output tlul_pkg::tl_d2h_t tl_o,
21:
22: // AST interface
23: input pwr_ast_rsp_t pwr_ast_i,
24: output pwr_ast_req_t pwr_ast_o,
25:
26: // rstmgr interface
27: input pwr_rst_rsp_t pwr_rst_i,
28: output pwr_rst_req_t pwr_rst_o,
29:
30: // clkmgr interface
31: output pwr_clk_req_t pwr_clk_o,
32: input pwr_clk_rsp_t pwr_clk_i,
33:
34: // otp interface
35: input pwr_otp_rsp_t pwr_otp_i,
36: output pwr_otp_req_t pwr_otp_o,
37:
38: // life cycle interface
39: input pwr_lc_rsp_t pwr_lc_i,
40: output pwr_lc_req_t pwr_lc_o,
41:
42: // flash interface
43: input pwr_flash_t pwr_flash_i,
44:
45: // processor interface
46: input pwr_cpu_t pwr_cpu_i,
47:
48: // peripherals interface, includes pinmux
49: input pwr_peri_t pwr_peri_i,
50:
51: output intr_wakeup_o
52:
53: );
54:
55: import pwrmgr_reg_pkg::*;
56:
57: ////////////////////////////
58: /// clk_i domain declarations
59: ////////////////////////////
60:
61: pwrmgr_reg2hw_t reg2hw;
62: pwrmgr_hw2reg_t hw2reg;
63: pwr_peri_t peri_reqs_masked;
64:
65: logic req_pwrup;
66: logic ack_pwrup;
67: logic req_pwrdn;
68: logic ack_pwrdn;
69: pwrup_cause_e pwrup_cause;
70:
71: logic capture_en_pulse; // begin capture wakeup causes
72: logic low_power_fall_through;
73: logic low_power_abort;
74:
75: ////////////////////////////
76: /// clk_slow_i domain declarations
77: ////////////////////////////
78:
79: // Captured signals
80: // These signals, though on clk_i domain, are safe for clk_slow_i to use
81: pwrmgr_reg2hw_wakeup_en_reg_t slow_wakeup_en;
82: pwrmgr_reg2hw_reset_en_reg_t slow_reset_en;
83:
84: pwr_ast_rsp_t slow_ast;
85: pwr_peri_t slow_peri_reqs, slow_peri_reqs_masked;
86:
87: pwrup_cause_e slow_pwrup_cause;
88: logic slow_pwrup_cause_toggle;
89: logic slow_req_pwrup;
90: logic slow_ack_pwrup;
91: logic slow_req_pwrdn;
92: logic slow_ack_pwrdn;
93: logic slow_main_pd_n;
94: logic slow_io_clk_en;
95: logic slow_core_clk_en;
96:
97: ////////////////////////////
98: /// Register module
99: ////////////////////////////
100:
101: logic low_power_hint;
102: logic lowpwr_cfg_wen;
103: logic clr_hint;
104: logic wkup;
105: logic clr_cfg_lock;
106:
107: pwrmgr_reg_top i_reg (
108: .clk_i,
109: .rst_ni,
110: .tl_i,
111: .tl_o,
112: .reg2hw,
113: .hw2reg,
114: .devmode_i (1'b1)
115: );
116:
117: // whenever low power entry begins, wipe the hint
118: assign hw2reg.control.low_power_hint.d = 1'b0;
119: assign hw2reg.control.low_power_hint.de = clr_hint;
120:
121: always_ff @(posedge clk_i or negedge rst_ni) begin
122: if (!rst_ni) begin
123: lowpwr_cfg_wen <= 1'b1;
124: end else if (!lowpwr_cfg_wen && (clr_cfg_lock || wkup)) begin
125: lowpwr_cfg_wen <= 1'b1;
126: end else if (low_power_hint) begin
127: lowpwr_cfg_wen <= 1'b0;
128: end
129: end
130:
131: assign hw2reg.ctrl_cfg_regwen.d = lowpwr_cfg_wen;
132:
133: ////////////////////////////
134: /// cdc handling
135: ////////////////////////////
136:
137: pwrmgr_cdc i_cdc (
138: .clk_i,
139: .rst_ni,
140: .clk_slow_i,
141: .rst_slow_ni,
142:
143: // slow domain signals
144: .slow_req_pwrup_i(slow_req_pwrup),
145: .slow_ack_pwrdn_i(slow_ack_pwrdn),
146: .slow_pwrup_cause_toggle_i(slow_pwrup_cause_toggle),
147: .slow_pwrup_cause_i(slow_pwrup_cause),
148: .slow_wakeup_en_o(slow_wakeup_en),
149: .slow_reset_en_o(slow_reset_en),
150: .slow_main_pd_no(slow_main_pd_n),
151: .slow_io_clk_en_o(slow_io_clk_en),
152: .slow_core_clk_en_o(slow_core_clk_en),
153: .slow_req_pwrdn_o(slow_req_pwrdn),
154: .slow_ack_pwrup_o(slow_ack_pwrup),
155: .slow_ast_o(slow_ast),
156: .slow_peri_reqs_o(slow_peri_reqs),
157: .slow_peri_reqs_masked_i(slow_peri_reqs_masked),
158:
159: // fast domain signals
160: .req_pwrdn_i(req_pwrdn),
161: .ack_pwrup_i(ack_pwrup),
162: .cfg_cdc_sync_i(reg2hw.cfg_cdc_sync.qe & reg2hw.cfg_cdc_sync.q),
163: .cdc_sync_done_o(hw2reg.cfg_cdc_sync.de),
164: .wakeup_en_i(reg2hw.wakeup_en.q),
165: .reset_en_i(reg2hw.reset_en.q),
166: .main_pd_ni(reg2hw.control.main_pd_n.q),
167: .io_clk_en_i(reg2hw.control.io_clk_en.q),
168: .core_clk_en_i(reg2hw.control.core_clk_en.q),
169: .ack_pwrdn_o(ack_pwrdn),
170: .req_pwrup_o(req_pwrup),
171: .pwrup_cause_o(pwrup_cause),
172: .peri_reqs_o(peri_reqs_masked),
173:
174: // AST signals
175: .ast_i(pwr_ast_i),
176:
177: // peripheral signals
178: .peri_i(pwr_peri_i)
179: );
180:
181: assign hw2reg.cfg_cdc_sync.d = 1'b0;
182:
183: ////////////////////////////
184: /// Wakup and reset capture
185: ////////////////////////////
186:
187: // reset and wakeup requests are captured into the slow clock domain and then
188: // fanned out to other domains as necessary. This ensures there is not a huge
189: // time gap between when the slow clk domain sees the signal vs when the fast
190: // clock domains see it. This creates redundant syncing but keeps the time
191: // scale approximately the same across all domains.
192: //
193: // This also implies that these signals must be at least 1 clk_slow pulse long
194: //
195: // Since resets are not latched inside pwrmgr, there exists a corner case where
196: // non-always-on reset requests may get wiped out by a graceful low power entry
197: // It's not clear if this is really an issue at the moment, but something to keep
198: // in mind if future changes are needed.
199: //
200: // Latching the reset requests is not difficult, but the bigger question is who
201: // should clear it and when that should happen. If the clearing does not work
202: // correctly, it is possible for the device to end up in a permanent reset loop,
203: // and that would be very undesirable.
204:
205: assign slow_peri_reqs_masked.wakeups = slow_peri_reqs.wakeups & slow_wakeup_en;
206: assign slow_peri_reqs_masked.rstreqs = slow_peri_reqs.rstreqs & slow_reset_en;
207:
208:
209:
210:
211: ////////////////////////////
212: /// clk_slow FSM
213: ////////////////////////////
214:
215: pwrmgr_slow_fsm i_slow_fsm (
216: .clk_i (clk_slow_i),
217: .rst_ni (rst_slow_ni),
218: .wakeup_i (|slow_peri_reqs_masked.wakeups),
219: .reset_req_i (|slow_peri_reqs_masked.rstreqs),
220: .ast_i (slow_ast),
221: .req_pwrup_o (slow_req_pwrup),
222: .pwrup_cause_o (slow_pwrup_cause),
223: .pwrup_cause_toggle_o (slow_pwrup_cause_toggle),
224: .ack_pwrup_i (slow_ack_pwrup),
225: .req_pwrdn_i (slow_req_pwrdn),
226: .ack_pwrdn_o (slow_ack_pwrdn),
227:
228: .main_pd_ni (slow_main_pd_n),
229: .io_clk_en_i (slow_io_clk_en),
230: .core_clk_en_i (slow_core_clk_en),
231:
232: // outputs to AST - These are on the slow clock domain
233: // TBD - need to check this with partners
234: .ast_o (pwr_ast_o)
235: );
236:
237:
238: ////////////////////////////
239: /// clk FSM
240: ////////////////////////////
241:
242: assign low_power_hint = reg2hw.control.low_power_hint.q == LowPower;
243:
244: pwrmgr_fsm i_fsm (
245: .clk_i,
246: .rst_ni,
247:
248: // interface with slow_fsm
249: .req_pwrup_i (req_pwrup),
250: .pwrup_cause_i (pwrup_cause), // por, wake or reset request
251: .ack_pwrup_o (ack_pwrup),
252: .req_pwrdn_o (req_pwrdn),
253: .ack_pwrdn_i (ack_pwrdn),
254: .low_power_entry_i (pwr_cpu_i.core_sleeping & low_power_hint),
255: .reset_req_i (|peri_reqs_masked.rstreqs),
256:
257: // cfg
258: .main_pd_ni (reg2hw.control.main_pd_n.q),
259:
260: // consumed in pwrmgr
261: .wkup_record_o (capture_en_pulse),
262: .wkup_o (wkup),
263: .clr_cfg_lock_o (clr_cfg_lock),
264: .fall_through_o (low_power_fall_through),
265: .abort_o (low_power_abort),
266: .clr_hint_o (clr_hint),
267:
268: // rstmgr
269: .pwr_rst_o (pwr_rst_o),
270: .pwr_rst_i (pwr_rst_i),
271:
272: // clkmgr
273: .ips_clk_en_o (pwr_clk_o.ip_clk_en),
274:
275: // otp
276: .otp_init_o (pwr_otp_o.otp_init),
277: .otp_done_i (pwr_otp_i.otp_done),
278: .otp_idle_i (pwr_otp_i.otp_idle),
279:
280: // lc
281: .lc_init_o (pwr_lc_o.lc_init),
282: .lc_done_i (pwr_lc_i.lc_done),
283: .lc_idle_i (pwr_lc_i.lc_idle),
284:
285: // flash
286: .flash_idle_i (pwr_flash_i.flash_idle)
287: );
288:
289: ////////////////////////////
290: /// Wakeup Info Capture
291: ////////////////////////////
292:
293: logic wake_info_wen;
294: logic [TotalWakeWidth-1:0] wake_info_data;
295:
296: assign wake_info_wen = reg2hw.wake_info.abort.qe |
297: reg2hw.wake_info.fall_through.qe |
298: reg2hw.wake_info.reasons.qe;
299:
300: assign wake_info_data = {reg2hw.wake_info.abort.q,
301: reg2hw.wake_info.fall_through.q,
302: reg2hw.wake_info.reasons.q};
303:
304: pwrmgr_wake_info i_wake_info (
305: .clk_i,
306: .rst_ni,
307: .wr_i (wake_info_wen),
308: .data_i (wake_info_data),
309: .start_capture_i (capture_en_pulse),
310: .record_dis_i (reg2hw.wake_info_capture_dis.q),
311: .wakeups_i (peri_reqs_masked.wakeups),
312: .fall_through_i (low_power_fall_through),
313: .abort_i (low_power_abort),
314: .info_o (hw2reg.wake_info)
315: );
316:
317: ////////////////////////////
318: /// Interrupts
319: ////////////////////////////
320:
321: // This interrupt is asserted whenever the fast FSM transitions
322: // into active state. However, it does not assert during POR
323: prim_intr_hw #(.Width(1)) intr_wakeup (
324: .event_intr_i (wkup),
325: .reg2hw_intr_enable_q_i (reg2hw.intr_enable.q),
326: .reg2hw_intr_test_q_i (reg2hw.intr_test.q),
327: .reg2hw_intr_test_qe_i (reg2hw.intr_test.qe),
328: .reg2hw_intr_state_q_i (reg2hw.intr_state.q),
329: .hw2reg_intr_state_de_o (hw2reg.intr_state.de),
330: .hw2reg_intr_state_d_o (hw2reg.intr_state.d),
331: .intr_o (intr_wakeup_o)
332: );
333:
334:
335: ////////////////////////////
336: /// Assertions
337: ////////////////////////////
338:
339:
340: endmodule // pwrmgr
341: