../src/lowrisc_ip_pwrmgr_0.1/rtl/pwrmgr_slow_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 Slow FSM
   6: //
   7: 
   8: `include "prim_assert.sv"
   9: 
  10: module 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,
  20:   output logic pwrup_cause_toggle_o,
  21:   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
  27:   input main_pd_ni,
  28:   input io_clk_en_i,
  29:   input core_clk_en_i,
  30: 
  31:   // AST interface
  32:   input pwr_ast_rsp_t ast_i,
  33:   output pwr_ast_req_t ast_o
  34: );
  35: 
  36:   // state enum
  37:   typedef enum logic [3:0] {
  38:     StReset,
  39:     StLowPower,
  40:     StMainPowerOn,
  41:     StClocksOn,
  42:     StReqPwrUp,
  43:     StIdle,
  44:     StAckPwrDn,
  45:     StClocksOff,
  46:     StMainPowerOff
  47:   } state_e;
  48: 
  49:   state_e state_q, state_d;
  50: 
  51:   // All signals crossing over to other domain must be flopped
  52:   pwrup_cause_e cause_q, cause_d;
  53:   logic cause_toggle_q, cause_toggle_d;
  54:   logic req_pwrup_q, req_pwrup_d;
  55:   logic ack_pwrdn_q, ack_pwrdn_d;
  56: 
  57:   // All power signals and signals going to analog logic are flopped to avoid transitional glitches
  58:   logic pd_nq, pd_nd;
  59:   logic pwr_clamp_q, pwr_clamp_d;
  60:   logic core_clk_en_q, core_clk_en_d;
  61:   logic io_clk_en_q, io_clk_en_d;
  62: 
  63:   logic all_clks_valid;
  64:   logic all_clks_invalid;
  65: 
  66:   // TODO: This should come from an AST package long term and not be hardcoded.
  67:   // Tracked in #2010
  68:   assign all_clks_valid = ast_i.core_clk_val == 2'b10 && ast_i.io_clk_val == 2'b10;
  69: 
  70:   // if clock were configured to turn off, make sure val is 2'b01
  71:   assign all_clks_invalid = (core_clk_en_i | ast_i.core_clk_val == 2'b01) &&
  72:                             (io_clk_en_i   | ast_i.io_clk_val == 2'b01);
  73: 
  74:   always_ff @(posedge clk_i or negedge rst_ni) begin
  75:     if (!rst_ni) begin
  76:       state_q        <= StReset;
  77:       cause_q        <= Por;
  78:       cause_toggle_q <= 1'b0;
  79:       pd_nq          <= 1'b0;
  80:       pwr_clamp_q    <= 1'b1;
  81:       core_clk_en_q  <= 1'b0;
  82:       io_clk_en_q    <= 1'b0;
  83:       req_pwrup_q    <= 1'b0;
  84:       ack_pwrdn_q    <= 1'b0;
  85:     end else begin
  86:       state_q        <= state_d;
  87:       cause_q        <= cause_d;
  88:       cause_toggle_q <= cause_toggle_d;
  89:       pd_nq          <= pd_nd;
  90:       pwr_clamp_q    <= pwr_clamp_d;
  91:       core_clk_en_q  <= core_clk_en_d;
  92:       io_clk_en_q    <= io_clk_en_d;
  93:       req_pwrup_q    <= req_pwrup_d;
  94:       ack_pwrdn_q    <= ack_pwrdn_d;
  95:     end
  96:   end
  97: 
  98:   always_comb begin
  99:     state_d        = state_q;
 100:     cause_d        = cause_q;
 101:     pd_nd          = pd_nq;
 102:     cause_toggle_d = cause_toggle_q;
 103:     pwr_clamp_d    = pwr_clamp_q;
 104:     core_clk_en_d  = core_clk_en_q;
 105:     io_clk_en_d    = io_clk_en_q;
 106: 
 107:     req_pwrup_d    = req_pwrup_q;
 108:     ack_pwrdn_d    = ack_pwrdn_q;
 109: 
 110:     unique case(state_q)
 111: 
 112:       StReset: begin
 113:         state_d = StMainPowerOn;
 114:         cause_d = Por;
 115:       end
 116: 
 117:       StLowPower: begin
 118:         // reset request behaves identically to a wakeup, other than the power-up cause being
 119:         // different
 120:         if (wakeup_i || reset_req_i) begin
 121:           state_d = StMainPowerOn;
 122:           cause_toggle_d = ~cause_toggle_q;
 123:           cause_d = reset_req_i ? Reset : Wake;
 124:         end
 125:       end
 126: 
 127:       StMainPowerOn: begin
 128:         pd_nd = 1'b1;
 129: 
 130:         if (ast_i.main_pok) begin
 131:           pwr_clamp_d = 1'b0;
 132:           state_d = StClocksOn;
 133:         end
 134:       end
 135: 
 136:       StClocksOn: begin
 137:         core_clk_en_d = 1'b1;
 138:         io_clk_en_d = 1'b1;
 139: 
 140:         if (all_clks_valid) begin
 141:           state_d = StReqPwrUp;
 142:         end
 143:       end
 144: 
 145:       StReqPwrUp: begin
 146:         req_pwrup_d = 1'b1;
 147: 
 148:         // req_pwrdn_i should be 0 here to indicate
 149:         // the request from the previous round has definitely completed
 150:         if (ack_pwrup_i && !req_pwrdn_i) begin
 151:           req_pwrup_d = 1'b0;
 152:           state_d = StIdle;
 153:         end
 154:       end
 155: 
 156:       StIdle: begin
 157:         // ack_pwrup_i should be 0 here to indicate
 158:         // the ack from the previous round has definitively completed
 159:         if (req_pwrdn_i && !ack_pwrup_i) begin
 160:           state_d = StAckPwrDn;
 161:         end
 162:       end
 163: 
 164:       StAckPwrDn: begin
 165:         ack_pwrdn_d = 1'b1;
 166: 
 167:         if (!req_pwrdn_i) begin
 168:           ack_pwrdn_d = 1'b0;
 169:           state_d = StClocksOff;
 170:         end
 171:       end
 172: 
 173:       StClocksOff: begin
 174:         core_clk_en_d = core_clk_en_i;
 175:         io_clk_en_d = io_clk_en_i;
 176: 
 177:         if (all_clks_invalid) begin
 178:           // if main power is turned off, assert clamp ahead
 179:           pwr_clamp_d = ~main_pd_ni;
 180:           state_d = StMainPowerOff;
 181:         end
 182:       end
 183: 
 184:       StMainPowerOff: begin
 185:         pd_nd = main_pd_ni;
 186: 
 187:         // if power is never turned off, proceed directly to low power state
 188:         if (!ast_i.main_pok | main_pd_ni) begin
 189:           state_d = StLowPower;
 190:         end
 191:       end
 192: 
 193:       // Very terminal state, kill everything
 194:       default: begin
 195:         pd_nd         = 1'b0;
 196:         pwr_clamp_d   = 1'b1;
 197:         core_clk_en_d = 1'b0;
 198:         io_clk_en_d   = 1'b0;
 199:       end
 200: 
 201: 
 202:     endcase // unique case (state_q)
 203:   end // always_comb
 204: 
 205: 
 206:   assign pwrup_cause_o = cause_q;
 207:   assign pwrup_cause_toggle_o = cause_toggle_q;
 208:   assign req_pwrup_o = req_pwrup_q;
 209:   assign ack_pwrdn_o = ack_pwrdn_q;
 210: 
 211:   assign ast_o.core_clk_en = core_clk_en_q;
 212:   assign ast_o.io_clk_en = io_clk_en_q;
 213:   assign ast_o.main_pd_n = pd_nq;
 214:   assign ast_o.pwr_clamp = pwr_clamp_q;
 215: 
 216:   // This is hardwired to 1 all the time
 217:   assign ast_o.slow_clk_en = 1'b1;
 218: 
 219: 
 220:   ////////////////////////////
 221:   ///  Unused
 222:   ////////////////////////////
 223: 
 224:   logic [1:0] unused_slow_clk_val;
 225:   assign unused_slow_clk_val = ast_i.slow_clk_val;
 226: 
 227: 
 228: endmodule
 229: