blob: 9a7dbee66da2f1f9bad1aed37d27977603fcd013 [file] [log] [blame]
Timothy Chenbc16a172020-04-07 23:45:23 -07001// 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 Slow FSM
6//
7
8`include "prim_assert.sv"
9
10module pwrmgr_slow_fsm import pwrmgr_pkg::*; (
11 input clk_i,
12 input rst_ni,
13
14 // sync'ed requests from peripherals
15 input wakeup_i,
16 input reset_req_i,
17
18 // interface with fast fsm
19 output logic req_pwrup_o,
Timothy Chen8837fbd2020-04-10 17:02:25 -070020 output logic pwrup_cause_toggle_o,
Timothy Chenbc16a172020-04-07 23:45:23 -070021 output pwrup_cause_e pwrup_cause_o,
22 input ack_pwrup_i,
23 input req_pwrdn_i,
24 output logic ack_pwrdn_o,
25
26 // low power entry configuration
Timothy Chen45a18312020-04-20 18:28:18 -070027 input main_pd_ni,
Timothy Chenbc16a172020-04-07 23:45:23 -070028 input io_clk_en_i,
29 input core_clk_en_i,
Timothy Chen93ee01e2020-09-21 18:01:04 -070030 input usb_clk_en_lp_i,
31 input usb_clk_en_active_i,
Timothy Chenbc16a172020-04-07 23:45:23 -070032
33 // AST interface
34 input pwr_ast_rsp_t ast_i,
35 output pwr_ast_req_t ast_o
36);
37
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -080038 slow_pwr_state_e state_q, state_d;
Timothy Chen45a18312020-04-20 18:28:18 -070039
40 // All signals crossing over to other domain must be flopped
Timothy Chen24343832020-04-09 18:14:37 -070041 pwrup_cause_e cause_q, cause_d;
Timothy Chen8837fbd2020-04-10 17:02:25 -070042 logic cause_toggle_q, cause_toggle_d;
Timothy Chen45a18312020-04-20 18:28:18 -070043 logic req_pwrup_q, req_pwrup_d;
44 logic ack_pwrdn_q, ack_pwrdn_d;
Timothy Chenbc16a172020-04-07 23:45:23 -070045
Timothy Chen45a18312020-04-20 18:28:18 -070046 // All power signals and signals going to analog logic are flopped to avoid transitional glitches
47 logic pd_nq, pd_nd;
Timothy Chen24343832020-04-09 18:14:37 -070048 logic pwr_clamp_q, pwr_clamp_d;
Timothy Chen0249a3a2021-04-15 11:26:31 -070049 logic pwr_clamp_env_q, pwr_clamp_env_d;
Timothy Chen24343832020-04-09 18:14:37 -070050 logic core_clk_en_q, core_clk_en_d;
51 logic io_clk_en_q, io_clk_en_d;
Timothy Chen93ee01e2020-09-21 18:01:04 -070052 logic usb_clk_en_q, usb_clk_en_d;
Timothy Chen24343832020-04-09 18:14:37 -070053
54 logic all_clks_valid;
55 logic all_clks_invalid;
56
Timothy Chen93ee01e2020-09-21 18:01:04 -070057 // all clocks sources are valid
Timothy Chen43e46a32020-12-03 10:32:14 -080058 // if clocks (usb) not configured to be active, then just bypass check
Timothy Chenea59ad32021-02-03 17:51:38 -080059 assign all_clks_valid = ast_i.core_clk_val &
60 ast_i.io_clk_val &
61 (~usb_clk_en_active_i | ast_i.usb_clk_val);
Timothy Chen24343832020-04-09 18:14:37 -070062
Timothy Chen43e46a32020-12-03 10:32:14 -080063 // if clocks were configured to turn off, make sure val is invalid
64 // if clocks were not configured to turn off, just bypass the check
Timothy Chenea59ad32021-02-03 17:51:38 -080065 assign all_clks_invalid = (core_clk_en_i | ~ast_i.core_clk_val) &
66 (io_clk_en_i | ~ast_i.io_clk_val) &
67 (usb_clk_en_lp_i | ~ast_i.usb_clk_val);
Timothy Chen24343832020-04-09 18:14:37 -070068
69 always_ff @(posedge clk_i or negedge rst_ni) begin
70 if (!rst_ni) begin
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -080071 state_q <= SlowPwrStateReset;
Timothy Chen8837fbd2020-04-10 17:02:25 -070072 cause_q <= Por;
73 cause_toggle_q <= 1'b0;
Timothy Chen72799e92021-02-09 10:38:44 -080074 // pwrmgr resets assuming main power domain is already ready
75 pd_nq <= 1'b1;
76 pwr_clamp_q <= 1'b0;
Timothy Chen0249a3a2021-04-15 11:26:31 -070077 pwr_clamp_env_q <= 1'b0;
Timothy Chen8837fbd2020-04-10 17:02:25 -070078 core_clk_en_q <= 1'b0;
79 io_clk_en_q <= 1'b0;
Timothy Chen93ee01e2020-09-21 18:01:04 -070080 usb_clk_en_q <= 1'b0;
Timothy Chen45a18312020-04-20 18:28:18 -070081 req_pwrup_q <= 1'b0;
82 ack_pwrdn_q <= 1'b0;
Timothy Chen24343832020-04-09 18:14:37 -070083 end else begin
Timothy Chen8837fbd2020-04-10 17:02:25 -070084 state_q <= state_d;
85 cause_q <= cause_d;
86 cause_toggle_q <= cause_toggle_d;
Timothy Chen45a18312020-04-20 18:28:18 -070087 pd_nq <= pd_nd;
Timothy Chen8837fbd2020-04-10 17:02:25 -070088 pwr_clamp_q <= pwr_clamp_d;
Timothy Chen0249a3a2021-04-15 11:26:31 -070089 pwr_clamp_env_q <= pwr_clamp_env_d;
Timothy Chen8837fbd2020-04-10 17:02:25 -070090 core_clk_en_q <= core_clk_en_d;
91 io_clk_en_q <= io_clk_en_d;
Timothy Chen93ee01e2020-09-21 18:01:04 -070092 usb_clk_en_q <= usb_clk_en_d;
Timothy Chen45a18312020-04-20 18:28:18 -070093 req_pwrup_q <= req_pwrup_d;
94 ack_pwrdn_q <= ack_pwrdn_d;
Timothy Chen24343832020-04-09 18:14:37 -070095 end
96 end
97
98 always_comb begin
Timothy Chen8837fbd2020-04-10 17:02:25 -070099 state_d = state_q;
100 cause_d = cause_q;
Timothy Chen45a18312020-04-20 18:28:18 -0700101 pd_nd = pd_nq;
Timothy Chen8837fbd2020-04-10 17:02:25 -0700102 cause_toggle_d = cause_toggle_q;
103 pwr_clamp_d = pwr_clamp_q;
Timothy Chen0249a3a2021-04-15 11:26:31 -0700104 pwr_clamp_env_d = pwr_clamp_env_q;
Timothy Chen8837fbd2020-04-10 17:02:25 -0700105 core_clk_en_d = core_clk_en_q;
106 io_clk_en_d = io_clk_en_q;
Timothy Chen93ee01e2020-09-21 18:01:04 -0700107 usb_clk_en_d = usb_clk_en_q;
Timothy Chen24343832020-04-09 18:14:37 -0700108
Timothy Chen45a18312020-04-20 18:28:18 -0700109 req_pwrup_d = req_pwrup_q;
110 ack_pwrdn_d = ack_pwrdn_q;
Timothy Chen24343832020-04-09 18:14:37 -0700111
112 unique case(state_q)
113
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800114 SlowPwrStateReset: begin
115 state_d = SlowPwrStateMainPowerOn;
Timothy Chen24343832020-04-09 18:14:37 -0700116 cause_d = Por;
117 end
118
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800119 SlowPwrStateLowPower: begin
Timothy Chen24343832020-04-09 18:14:37 -0700120 // reset request behaves identically to a wakeup, other than the power-up cause being
121 // different
122 if (wakeup_i || reset_req_i) begin
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800123 state_d = SlowPwrStateMainPowerOn;
Timothy Chen8837fbd2020-04-10 17:02:25 -0700124 cause_toggle_d = ~cause_toggle_q;
Timothy Chen24343832020-04-09 18:14:37 -0700125 cause_d = reset_req_i ? Reset : Wake;
126 end
127 end
128
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800129 SlowPwrStateMainPowerOn: begin
Timothy Chen45a18312020-04-20 18:28:18 -0700130 pd_nd = 1'b1;
Timothy Chen24343832020-04-09 18:14:37 -0700131
132 if (ast_i.main_pok) begin
Timothy Chen0249a3a2021-04-15 11:26:31 -0700133 pwr_clamp_env_d = 1'b0;
Timothy Chen07302ad2021-04-13 11:50:31 -0700134 state_d = SlowPwrStatePwrClampOff;
Timothy Chen24343832020-04-09 18:14:37 -0700135 end
136 end
137
Timothy Chen07302ad2021-04-13 11:50:31 -0700138 SlowPwrStatePwrClampOff: begin
139 pwr_clamp_d = 1'b0;
140 state_d = SlowPwrStateClocksOn;
141 end
142
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800143 SlowPwrStateClocksOn: begin
Timothy Chen24343832020-04-09 18:14:37 -0700144 core_clk_en_d = 1'b1;
145 io_clk_en_d = 1'b1;
Timothy Chen93ee01e2020-09-21 18:01:04 -0700146 usb_clk_en_d = usb_clk_en_active_i;
Timothy Chen24343832020-04-09 18:14:37 -0700147
148 if (all_clks_valid) begin
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800149 state_d = SlowPwrStateReqPwrUp;
Timothy Chen24343832020-04-09 18:14:37 -0700150 end
151 end
152
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800153 SlowPwrStateReqPwrUp: begin
Timothy Chen45a18312020-04-20 18:28:18 -0700154 req_pwrup_d = 1'b1;
Timothy Chen24343832020-04-09 18:14:37 -0700155
Timothy Chen45a18312020-04-20 18:28:18 -0700156 // req_pwrdn_i should be 0 here to indicate
157 // the request from the previous round has definitely completed
158 if (ack_pwrup_i && !req_pwrdn_i) begin
159 req_pwrup_d = 1'b0;
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800160 state_d = SlowPwrStateIdle;
Timothy Chen24343832020-04-09 18:14:37 -0700161 end
162 end
163
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800164 SlowPwrStateIdle: begin
Timothy Chen45a18312020-04-20 18:28:18 -0700165 // ack_pwrup_i should be 0 here to indicate
166 // the ack from the previous round has definitively completed
Timothy Chen93ee01e2020-09-21 18:01:04 -0700167 usb_clk_en_d = usb_clk_en_active_i;
168
Timothy Chen45a18312020-04-20 18:28:18 -0700169 if (req_pwrdn_i && !ack_pwrup_i) begin
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800170 state_d = SlowPwrStateAckPwrDn;
Timothy Chen24343832020-04-09 18:14:37 -0700171 end
172 end
173
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800174 SlowPwrStateAckPwrDn: begin
Timothy Chen45a18312020-04-20 18:28:18 -0700175 ack_pwrdn_d = 1'b1;
Timothy Chen24343832020-04-09 18:14:37 -0700176
177 if (!req_pwrdn_i) begin
Timothy Chen45a18312020-04-20 18:28:18 -0700178 ack_pwrdn_d = 1'b0;
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800179 state_d = SlowPwrStateClocksOff;
Timothy Chen24343832020-04-09 18:14:37 -0700180 end
181 end
182
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800183 SlowPwrStateClocksOff: begin
Timothy Chen24343832020-04-09 18:14:37 -0700184 core_clk_en_d = core_clk_en_i;
185 io_clk_en_d = io_clk_en_i;
Timothy Chen93ee01e2020-09-21 18:01:04 -0700186 usb_clk_en_d = usb_clk_en_lp_i;
Timothy Chen24343832020-04-09 18:14:37 -0700187
188 if (all_clks_invalid) begin
Timothy Chen07302ad2021-04-13 11:50:31 -0700189 // if main power is turned off, assert early clamp ahead
Timothy Chen0249a3a2021-04-15 11:26:31 -0700190 pwr_clamp_env_d = ~main_pd_ni;
Timothy Chen07302ad2021-04-13 11:50:31 -0700191 state_d = SlowPwrStatePwrClampOn;
Timothy Chen24343832020-04-09 18:14:37 -0700192 end
193 end
194
Timothy Chen07302ad2021-04-13 11:50:31 -0700195 SlowPwrStatePwrClampOn: begin
196 // if main power is turned off, assert clamp ahead
Timothy Chen0249a3a2021-04-15 11:26:31 -0700197 pwr_clamp_d = pwr_clamp_env_q;
Timothy Chen07302ad2021-04-13 11:50:31 -0700198 state_d = SlowPwrStateMainPowerOff;
199 end
200
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800201 SlowPwrStateMainPowerOff: begin
Timothy Chen45a18312020-04-20 18:28:18 -0700202 pd_nd = main_pd_ni;
Timothy Chen24343832020-04-09 18:14:37 -0700203
204 // if power is never turned off, proceed directly to low power state
Timothy Chen45a18312020-04-20 18:28:18 -0700205 if (!ast_i.main_pok | main_pd_ni) begin
Srikrishna Iyerd6b71f42021-01-06 15:33:26 -0800206 state_d = SlowPwrStateLowPower;
Timothy Chen24343832020-04-09 18:14:37 -0700207 end
208 end
209
210 // Very terminal state, kill everything
211 default: begin
Timothy Chen45a18312020-04-20 18:28:18 -0700212 pd_nd = 1'b0;
Timothy Chen24343832020-04-09 18:14:37 -0700213 pwr_clamp_d = 1'b1;
214 core_clk_en_d = 1'b0;
215 io_clk_en_d = 1'b0;
Timothy Chen93ee01e2020-09-21 18:01:04 -0700216 usb_clk_en_d = 1'b0;
Timothy Chen24343832020-04-09 18:14:37 -0700217 end
218
219
220 endcase // unique case (state_q)
221 end // always_comb
222
223
224 assign pwrup_cause_o = cause_q;
Timothy Chen8837fbd2020-04-10 17:02:25 -0700225 assign pwrup_cause_toggle_o = cause_toggle_q;
Timothy Chen45a18312020-04-20 18:28:18 -0700226 assign req_pwrup_o = req_pwrup_q;
227 assign ack_pwrdn_o = ack_pwrdn_q;
Timothy Chen24343832020-04-09 18:14:37 -0700228
229 assign ast_o.core_clk_en = core_clk_en_q;
230 assign ast_o.io_clk_en = io_clk_en_q;
Timothy Chen93ee01e2020-09-21 18:01:04 -0700231 assign ast_o.usb_clk_en = usb_clk_en_q;
Timothy Chen45a18312020-04-20 18:28:18 -0700232 assign ast_o.main_pd_n = pd_nq;
Timothy Chen0249a3a2021-04-15 11:26:31 -0700233 assign ast_o.pwr_clamp_env = pwr_clamp_env_q;
Timothy Chen24343832020-04-09 18:14:37 -0700234 assign ast_o.pwr_clamp = pwr_clamp_q;
Timothy Chen24343832020-04-09 18:14:37 -0700235 // This is hardwired to 1 all the time
236 assign ast_o.slow_clk_en = 1'b1;
237
238
239 ////////////////////////////
240 /// Unused
241 ////////////////////////////
242
Timothy Chenea59ad32021-02-03 17:51:38 -0800243 logic unused_slow_clk_val;
Timothy Chen24343832020-04-09 18:14:37 -0700244 assign unused_slow_clk_val = ast_i.slow_clk_val;
Timothy Chenbc16a172020-04-07 23:45:23 -0700245
246
247endmodule