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