../src/lowrisc_ip_pwrmgr_0.1/rtl/pwrmgr_fsm.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 Fast FSM
6: //
7:
8: `include "prim_assert.sv"
9:
10: module pwrmgr_fsm import pwrmgr_pkg::*; (
11: input clk_i,
12: input rst_ni,
13:
14: // interface with slow_fsm
15: input req_pwrup_i,
16: input pwrup_cause_e pwrup_cause_i,
17: output logic ack_pwrup_o,
18: output logic req_pwrdn_o,
19: input ack_pwrdn_i,
20: input low_power_entry_i,
21: input main_pd_ni,
22: input reset_req_i,
23:
24: // consumed in pwrmgr
25: output logic wkup_o, // generate wake interrupt
26: output logic wkup_record_o, // enable wakeup recording
27: output logic fall_through_o,
28: output logic abort_o,
29: output logic clr_hint_o,
30: output logic clr_cfg_lock_o,
31:
32: // rstmgr
33: output pwr_rst_req_t pwr_rst_o,
34: input pwr_rst_rsp_t pwr_rst_i,
35:
36: // clkmgr
37: output logic ips_clk_en_o,
38:
39: // otp
40: output logic otp_init_o,
41: input otp_done_i,
42: input otp_idle_i,
43:
44: // lc
45: output logic lc_init_o,
46: input lc_done_i,
47: input lc_idle_i,
48:
49: // flash
50: input flash_idle_i
51: );
52:
53: // state enum
54: typedef enum logic [4:0] {
55: StLowPower,
56: StEnableClocks,
57: StReleaseLcRst,
58: StOtpInit,
59: StLcInit,
60: StAckPwrUp,
61: StActive,
62: StDisClks,
63: StFallThrough,
64: StNvmIdleChk,
65: StLowPowerPrep,
66: StNvmShutDown,
67: StResetPrep,
68: StReqPwrDn
69: } state_e;
70:
71: // The code below always assumes the always on domain is index 0
72: `ASSERT_INIT(AlwaysOnIndex_A, ALWAYS_ON_DOMAIN == 0)
73:
74: // when there are multiple on domains, the latter 1 should become another parameter
75: localparam int OffDomainSelStart = ALWAYS_ON_DOMAIN + 1;
76:
77: // all powered down domains have resets asserted
78: logic pd_n_rsts_asserted;
79:
80: // all domains have resets asserted
81: logic all_rsts_asserted;
82:
83: // resets are valid
84: logic reset_valid;
85:
86: // reset hint to rstmgr
87: reset_cause_e reset_cause_q, reset_cause_d;
88:
89: state_e state_d, state_q;
90: logic reset_ongoing_q, reset_ongoing_d;
91: logic req_pwrdn_q, req_pwrdn_d;
92: logic ack_pwrup_q, ack_pwrup_d;
93: logic ip_clk_en_q, ip_clk_en_d;
94: logic [PowerDomains-1:0] rst_lc_req_q, rst_sys_req_q;
95: logic [PowerDomains-1:0] rst_lc_req_d, rst_sys_req_d;
96: logic otp_init;
97: logic lc_init;
98:
99: assign pd_n_rsts_asserted = pwr_rst_i.rst_lc_src_n[PowerDomains-1:1] == '0 &
100: pwr_rst_i.rst_sys_src_n[PowerDomains-1:1] == '0;
101:
102: assign all_rsts_asserted = pwr_rst_i.rst_lc_src_n == '0 &
103: pwr_rst_i.rst_sys_src_n == '0;
104:
105: // when in low power path, resets are controlled by domain power down
106: // when in reset path, all resets must be asserted
107: // when the reset cause is something else, it is invalid
108: assign reset_valid = reset_cause_q == LowPwrEntry ? main_pd_ni | pd_n_rsts_asserted :
109: reset_cause_q == HwReq ? all_rsts_asserted : 1'b0;
110:
111:
112: always_ff @(posedge clk_i or negedge rst_ni) begin
113: if (!rst_ni) begin
114: state_q <= StLowPower;
115: ack_pwrup_q <= 1'b0;
116: req_pwrdn_q <= 1'b0;
117: reset_ongoing_q <= 1'b0;
118: ip_clk_en_q <= 1'b0;
119: rst_lc_req_q <= {PowerDomains{1'b1}};
120: rst_sys_req_q <= {PowerDomains{1'b1}};
121: reset_cause_q <= ResetUndefined;
122: end else begin
123: state_q <= state_d;
124: ack_pwrup_q <= ack_pwrup_d;
125: req_pwrdn_q <= req_pwrdn_d;
126: reset_ongoing_q <= reset_ongoing_d;
127: ip_clk_en_q <= ip_clk_en_d;
128: rst_lc_req_q <= rst_lc_req_d;
129: rst_sys_req_q <= rst_sys_req_d;
130: reset_cause_q <= reset_cause_d;
131: end
132: end
133:
134: always_comb begin
135: otp_init = 1'b0;
136: lc_init = 1'b0;
137: wkup_o = 1'b0;
138: wkup_record_o = 1'b0;
139: fall_through_o = 1'b0;
140: abort_o = 1'b0;
141: clr_hint_o = 1'b0;
142: clr_cfg_lock_o = 1'b0;
143:
144: state_d = state_q;
145: ack_pwrup_d = ack_pwrup_q;
146: req_pwrdn_d = req_pwrdn_q;
147: reset_ongoing_d = reset_ongoing_q;
148: ip_clk_en_d = ip_clk_en_q;
149: rst_lc_req_d = rst_lc_req_q;
150: rst_sys_req_d = rst_sys_req_q;
151: reset_cause_d = reset_cause_q;
152:
153: unique case(state_q)
154:
155: StLowPower: begin
156: if (req_pwrup_i || reset_ongoing_q) begin
157: state_d = StEnableClocks;
158: end
159: end
160:
161: StEnableClocks: begin
162: ip_clk_en_d = 1'b1;
163:
164: if (1'b1) begin // TODO, add a feedback signal to check clocks are enabled
165: state_d = StReleaseLcRst;
166: end
167: end
168:
169: StReleaseLcRst: begin
170: rst_lc_req_d = '0; // release rst_lc_n for all power domains
171:
172: if (&pwr_rst_i.rst_lc_src_n) begin // once all resets are released
173: state_d = StOtpInit;
174: end
175: end
176:
177: StOtpInit: begin
178: otp_init = 1'b1;
179:
180: if (otp_done_i) begin
181: state_d = StLcInit;
182: end
183: end
184:
185: StLcInit: begin
186: lc_init = 1'b1;
187:
188: if (lc_done_i) begin
189: state_d = StAckPwrUp;
190:
191:
192: end
193: end
194:
195: StAckPwrUp: begin
196: // only ack the slow_fsm if we actually transitioned through it
197: ack_pwrup_d = !reset_ongoing_q;
198:
199: // wait for request power up to drop relative to ack
200: if (!req_pwrup_i || reset_ongoing_q) begin
201: ack_pwrup_d = 1'b0;
202: clr_cfg_lock_o = 1'b1;
203: wkup_o = pwrup_cause_i == Wake;
204: state_d = StActive;
205: end
206: end
207:
208: StActive: begin
209: rst_sys_req_d = '0;
210: reset_cause_d = ResetNone;
211:
212: if (reset_req_i || low_power_entry_i) begin
213: reset_cause_d = ResetUndefined;
214: state_d = StDisClks;
215: end
216: end
217:
218: StDisClks: begin
219: ip_clk_en_d = 1'b0;
220:
221: if (1'b1) begin // TODO, add something to check that clocks are disabled
222: state_d = reset_req_i ? StNvmShutDown : StFallThrough;
223: wkup_record_o = !reset_req_i;
224: end
225: end
226:
227: // Low Power Path
228: StFallThrough: begin
229: clr_hint_o = 1'b1;
230:
231: // the processor was interrupted after it asserted WFI and is executing again
232: if (!low_power_entry_i) begin
233: ip_clk_en_d = 1'b1;
234: wkup_o = 1'b1;
235: fall_through_o = 1'b1;
236: state_d = StActive;
237: end else begin
238: state_d = StNvmIdleChk;
239: end
240: end
241:
242: StNvmIdleChk: begin
243:
244: if (otp_idle_i && lc_idle_i && flash_idle_i) begin
245: state_d = StLowPowerPrep;
246: end else begin
247: ip_clk_en_d = 1'b1;
248: wkup_o = 1'b1;
249: abort_o = 1'b1;
250: state_d = StActive;
251: end
252: end
253:
254: StLowPowerPrep: begin
255: reset_cause_d = LowPwrEntry;
256:
257: // reset non-always-on domains if requested
258: // this includes the clock manager, which implies pwr/rst managers must
259: // be fed directly from the source
260: for (int i = OffDomainSelStart; i < PowerDomains; i++) begin
261: rst_lc_req_d[i] = ~main_pd_ni;
262: rst_sys_req_d[i] = ~main_pd_ni;
263: end
264:
265: if (reset_valid) begin
266: state_d = StReqPwrDn;
267: end
268: end
269:
270: StReqPwrDn: begin
271: req_pwrdn_d = 1'b1;
272:
273: if (ack_pwrdn_i) begin
274: req_pwrdn_d = 1'b0;
275: state_d = StLowPower;
276: end
277: end
278:
279: // Reset Path
280: // This state is TODO, the details are still under discussion
281: StNvmShutDown: begin
282: clr_hint_o = 1'b1;
283: reset_ongoing_d = 1'b1;
284: state_d = StResetPrep;
285: end
286:
287: StResetPrep: begin
288: reset_cause_d = HwReq;
289: rst_lc_req_d = {PowerDomains{1'b1}};
290: rst_sys_req_d = {PowerDomains{1'b1}};
291:
292: if (reset_valid) begin
293: state_d = StLowPower;
294: end
295: end
296:
297: // Terminal state, kill everything
298: default: begin
299: rst_lc_req_d = {PowerDomains{1'b1}};
300: rst_sys_req_d = {PowerDomains{1'b1}};
301: ip_clk_en_d = 1'b0;
302: end
303:
304: endcase // unique case (state_q)
305: end // always_comb
306:
307: assign ack_pwrup_o = ack_pwrup_q;
308: assign req_pwrdn_o = req_pwrdn_q;
309:
310: assign pwr_rst_o.rst_lc_req = rst_lc_req_q;
311: assign pwr_rst_o.rst_sys_req = rst_sys_req_q;
312: assign pwr_rst_o.reset_cause = reset_cause_q;
313:
314: assign otp_init_o = otp_init;
315: assign lc_init_o = lc_init;
316: assign ips_clk_en_o = ip_clk_en_q;
317:
318:
319: endmodule
320: