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