[pwrmgr] Add pwrmgr_cdc module
- contains all cdc handling logic
- moved to a more traditional synchronization scheme
Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/ip/pwrmgr/data/pwrmgr.hjson b/hw/ip/pwrmgr/data/pwrmgr.hjson
index 620b4ac..db5df8b 100644
--- a/hw/ip/pwrmgr/data/pwrmgr.hjson
+++ b/hw/ip/pwrmgr/data/pwrmgr.hjson
@@ -70,6 +70,34 @@
regwidth: "32",
registers: [
+ { name: "CFG_CDC_SYNC",
+ swaccess: "rw",
+ hwaccess: "hrw",
+ hwqe: "true",
+ desc: '''
+ The configuration registers CONTROL, WAKEUP_EN, RESET_EN are all written in the
+ fast clock domain but used in the slow clock domain.
+
+ The configuration are not propogated across the clock boundary until this
+ register is triggered and read. See fields below for more details
+ ''',
+
+ fields: [
+ { bits: "0",
+ swaccess: "wo",
+ name: "SYNC",
+ desc: '''
+ Configuration sync. When this bit is written to 1, a sync pulse is generated. When
+ the sync completes, this bit then self clears.
+
+ Software should write this bit to 1, wait for it to clear, before assuming the slow clock
+ domain has assumed the programmaed values.
+ ''',
+ resval: "0",
+ },
+ ]
+ },
+
{ name: "CTRL_CFG_REGWEN",
swaccess: "rw0c",
hwaccess: "hwo",
diff --git a/hw/ip/pwrmgr/fpv/vip/pwrmgr_csr_assert_fpv.sv b/hw/ip/pwrmgr/fpv/vip/pwrmgr_csr_assert_fpv.sv
index a215592..60131f2 100644
--- a/hw/ip/pwrmgr/fpv/vip/pwrmgr_csr_assert_fpv.sv
+++ b/hw/ip/pwrmgr/fpv/vip/pwrmgr_csr_assert_fpv.sv
@@ -87,45 +87,49 @@
// read/write assertions for register: intr_test
`ASSERT(intr_test_wr_A, wr_ext_P(0, 6'h8, i_pwrmgr.reg2hw.intr_test.q, 0))
+ // read/write assertions for register: cfg_cdc_sync
+ `ASSERT(cfg_cdc_sync_wr_A, wr_P(0, 6'hc, i_pwrmgr.reg2hw.cfg_cdc_sync.q, 0))
+ `ASSERT(cfg_cdc_sync_rd_A, rd_P(0, 6'hc, i_pwrmgr.hw2reg.cfg_cdc_sync.d))
+
// read/write assertions for register: ctrl_cfg_regwen
- `ASSERT(ctrl_cfg_regwen_wr_A, wr_ext_P(0, 6'hc, i_pwrmgr.reg2hw.ctrl_cfg_regwen.q, 0))
- `ASSERT(ctrl_cfg_regwen_rd_A, rd_ext_P(0, 6'hc, i_pwrmgr.hw2reg.ctrl_cfg_regwen.d))
+ `ASSERT(ctrl_cfg_regwen_wr_A, wr_ext_P(0, 6'h10, i_pwrmgr.reg2hw.ctrl_cfg_regwen.q, 0))
+ `ASSERT(ctrl_cfg_regwen_rd_A, rd_ext_P(0, 6'h10, i_pwrmgr.hw2reg.ctrl_cfg_regwen.d))
// read/write assertions for register: control
- `ASSERT(control_wr_A, wr_P(6, 6'h10, i_pwrmgr.reg2hw.control.q, i_pwrmgr.i_reg_top.ctrl_cfg_regwen_qs))
+ `ASSERT(control_wr_A, wr_P(6, 6'h14, i_pwrmgr.reg2hw.control.q, i_pwrmgr.i_reg_top.ctrl_cfg_regwen_qs))
`ASSERT(control_stable_A, wr_regen_stable_P(i_pwrmgr.i_reg_top.ctrl_cfg_regwen_qs, i_pwrmgr.reg2hw.control.q))
- `ASSERT(control_rd_A, rd_P(6, 6'h10, i_pwrmgr.hw2reg.control.d))
+ `ASSERT(control_rd_A, rd_P(6, 6'h14, i_pwrmgr.hw2reg.control.d))
// read/write assertions for register: wakeup_en_regwen
- `ASSERT(wakeup_en_regwen_wr_A, wr_P(0, 6'h14, i_pwrmgr.i_reg_top.wakeup_en_regwen_we, 0))
- `ASSERT(wakeup_en_regwen_rd_A, rd_P(0, 6'h14, i_pwrmgr.i_reg_top.wakeup_en_regwen_qs))
+ `ASSERT(wakeup_en_regwen_wr_A, wr_P(0, 6'h18, i_pwrmgr.i_reg_top.wakeup_en_regwen_we, 0))
+ `ASSERT(wakeup_en_regwen_rd_A, rd_P(0, 6'h18, i_pwrmgr.i_reg_top.wakeup_en_regwen_qs))
// read/write assertions for register: wakeup_en
- `ASSERT(wakeup_en_wr_A, wr_P(15, 6'h18, i_pwrmgr.reg2hw.wakeup_en.q, i_pwrmgr.i_reg_top.wakeup_en_regwen_qs))
+ `ASSERT(wakeup_en_wr_A, wr_P(15, 6'h1c, i_pwrmgr.reg2hw.wakeup_en.q, i_pwrmgr.i_reg_top.wakeup_en_regwen_qs))
`ASSERT(wakeup_en_stable_A, wr_regen_stable_P(i_pwrmgr.i_reg_top.wakeup_en_regwen_qs, i_pwrmgr.reg2hw.wakeup_en.q))
- `ASSERT(wakeup_en_rd_A, rd_P(15, 6'h18, i_pwrmgr.reg2hw.wakeup_en.q))
+ `ASSERT(wakeup_en_rd_A, rd_P(15, 6'h1c, i_pwrmgr.reg2hw.wakeup_en.q))
// read/write assertions for register: wake_status
- `ASSERT(wake_status_rd_A, rd_P(15, 6'h1c, i_pwrmgr.i_reg_top.wake_status_qs))
+ `ASSERT(wake_status_rd_A, rd_P(15, 6'h20, i_pwrmgr.i_reg_top.wake_status_qs))
// read/write assertions for register: reset_en_regwen
- `ASSERT(reset_en_regwen_wr_A, wr_P(0, 6'h20, i_pwrmgr.i_reg_top.reset_en_regwen_we, 0))
- `ASSERT(reset_en_regwen_rd_A, rd_P(0, 6'h20, i_pwrmgr.i_reg_top.reset_en_regwen_qs))
+ `ASSERT(reset_en_regwen_wr_A, wr_P(0, 6'h24, i_pwrmgr.i_reg_top.reset_en_regwen_we, 0))
+ `ASSERT(reset_en_regwen_rd_A, rd_P(0, 6'h24, i_pwrmgr.i_reg_top.reset_en_regwen_qs))
// read/write assertions for register: reset_en
- `ASSERT(reset_en_wr_A, wr_P(1, 6'h24, i_pwrmgr.reg2hw.reset_en.q, i_pwrmgr.i_reg_top.reset_en_regwen_qs))
+ `ASSERT(reset_en_wr_A, wr_P(1, 6'h28, i_pwrmgr.reg2hw.reset_en.q, i_pwrmgr.i_reg_top.reset_en_regwen_qs))
`ASSERT(reset_en_stable_A, wr_regen_stable_P(i_pwrmgr.i_reg_top.reset_en_regwen_qs, i_pwrmgr.reg2hw.reset_en.q))
- `ASSERT(reset_en_rd_A, rd_P(1, 6'h24, i_pwrmgr.reg2hw.reset_en.q))
+ `ASSERT(reset_en_rd_A, rd_P(1, 6'h28, i_pwrmgr.reg2hw.reset_en.q))
// read/write assertions for register: reset_status
- `ASSERT(reset_status_rd_A, rd_P(1, 6'h28, i_pwrmgr.i_reg_top.reset_status_qs))
+ `ASSERT(reset_status_rd_A, rd_P(1, 6'h2c, i_pwrmgr.i_reg_top.reset_status_qs))
// read/write assertions for register: wake_info_capture_dis
- `ASSERT(wake_info_capture_dis_wr_A, wr_P(0, 6'h2c, i_pwrmgr.reg2hw.wake_info_capture_dis.q, 0))
- `ASSERT(wake_info_capture_dis_rd_A, rd_P(0, 6'h2c, i_pwrmgr.reg2hw.wake_info_capture_dis.q))
+ `ASSERT(wake_info_capture_dis_wr_A, wr_P(0, 6'h30, i_pwrmgr.reg2hw.wake_info_capture_dis.q, 0))
+ `ASSERT(wake_info_capture_dis_rd_A, rd_P(0, 6'h30, i_pwrmgr.reg2hw.wake_info_capture_dis.q))
// read/write assertions for register: wake_info
- `ASSERT(wake_info_wr_A, wr_ext_P(17, 6'h30, i_pwrmgr.reg2hw.wake_info.q, 0))
- `ASSERT(wake_info_rd_A, rd_ext_P(17, 6'h30, i_pwrmgr.hw2reg.wake_info.d))
+ `ASSERT(wake_info_wr_A, wr_ext_P(17, 6'h34, i_pwrmgr.reg2hw.wake_info.q, 0))
+ `ASSERT(wake_info_rd_A, rd_ext_P(17, 6'h34, i_pwrmgr.hw2reg.wake_info.d))
endmodule
diff --git a/hw/ip/pwrmgr/pwrmgr.core b/hw/ip/pwrmgr/pwrmgr.core
index 31fc4e1..c751ef7 100644
--- a/hw/ip/pwrmgr/pwrmgr.core
+++ b/hw/ip/pwrmgr/pwrmgr.core
@@ -15,7 +15,7 @@
- rtl/pwrmgr_reg_pkg.sv
- rtl/pwrmgr_reg_top.sv
- rtl/pwrmgr.sv
- - rtl/pwrmgr_cdc_pulse.sv
+ - rtl/pwrmgr_cdc.sv
- rtl/pwrmgr_slow_fsm.sv
- rtl/pwrmgr_fsm.sv
- rtl/pwrmgr_wake_info.sv
diff --git a/hw/ip/pwrmgr/rtl/pwrmgr.sv b/hw/ip/pwrmgr/rtl/pwrmgr.sv
index 26b210f..4f3fb79 100644
--- a/hw/ip/pwrmgr/rtl/pwrmgr.sv
+++ b/hw/ip/pwrmgr/rtl/pwrmgr.sv
@@ -60,7 +60,7 @@
pwrmgr_reg2hw_t reg2hw;
pwrmgr_hw2reg_t hw2reg;
- pwr_peri_rsp_t ext_reqs, ext_reqs_masked;
+ pwr_peri_rsp_t ext_reqs_masked;
logic req_pwrup;
logic ack_pwrup;
logic req_pwrdn;
@@ -80,10 +80,11 @@
pwrmgr_reg2hw_wakeup_en_reg_t slow_wakeup_en;
pwrmgr_reg2hw_reset_en_reg_t slow_reset_en;
- pwr_ast_rsp_t slow_ast_q;
+ pwr_ast_rsp_t slow_ast;
pwr_peri_rsp_t slow_ext_reqs, slow_ext_reqs_masked;
pwrup_cause_e slow_pwrup_cause;
+ logic slow_pwrup_cause_toggle;
logic slow_req_pwrup;
logic slow_ack_pwrup;
logic slow_req_pwrdn;
@@ -129,78 +130,54 @@
assign hw2reg.ctrl_cfg_regwen.d = lowpwr_cfg_regwen;
////////////////////////////
- /// cdc handling - clk_i
+ /// cdc handling
////////////////////////////
- // finds a clk_slow edge in clk domain to know when it is safe to sync over
- // this signal is only safe to use within the pwrmgr module when the source
- // and destination clock domains are both clear
- logic cdc_safe;
-
- // pwrup is synced directly as it acts as a start signal to the pulse module
- prim_flop_2sync # (
- .Width(1)
- ) i_pwrup_sync (
+ pwrmgr_cdc i_cdc (
.clk_i,
.rst_ni,
- .d(slow_req_pwrup),
- .q(req_pwrup)
- );
-
- pwrmgr_cdc_pulse i_cdc_pulse (
.clk_slow_i,
- .clk_i,
- .rst_ni,
- .start_i(req_pwrup),
- .stop_i(req_pwrdn),
- .pulse_o(cdc_safe)
+ .rst_slow_ni,
+
+ // slow domain signals
+ .slow_req_pwrup_i(slow_req_pwrup),
+ .slow_ack_pwrdn_i(slow_ack_pwrdn),
+ .slow_pwrup_cause_toggle_i(slow_pwrup_cause_toggle),
+ .slow_pwrup_cause_i(slow_pwrup_cause),
+ .slow_wakeup_en_o(slow_wakeup_en),
+ .slow_reset_en_o(slow_reset_en),
+ .slow_main_pdb_o(slow_main_pdb),
+ .slow_io_clk_en_o(slow_io_clk_en),
+ .slow_core_clk_en_o(slow_core_clk_en),
+ .slow_req_pwrdn_o(slow_req_pwrdn),
+ .slow_ack_pwrup_o(slow_ack_pwrup),
+ .slow_ast_o(slow_ast),
+ .slow_ext_reqs_o(slow_ext_reqs),
+ .slow_ext_reqs_masked_i(slow_ext_reqs_masked),
+
+ // fast domain signals
+ .req_pwrdn_i(req_pwrdn),
+ .ack_pwrup_i(ack_pwrup),
+ .cfg_cdc_sync_i(reg2hw.cfg_cdc_sync.qe & reg2hw.cfg_cdc_sync.q),
+ .cdc_sync_done_o(hw2reg.cfg_cdc_sync.de),
+ .wakeup_en_i(reg2hw.wakeup_en.q),
+ .reset_en_i(reg2hw.reset_en.q),
+ .main_pdb_i(reg2hw.control.main_pdb.q),
+ .io_clk_en_i(reg2hw.control.io_clk_en.q),
+ .core_clk_en_i(reg2hw.control.core_clk_en.q),
+ .ack_pwrdn_o(ack_pwrdn),
+ .req_pwrup_o(req_pwrup),
+ .pwrup_cause_o(pwrup_cause),
+ .ext_reqs_o(ext_reqs_masked),
+
+ // AST signals
+ .ast_i(pwr_ast_i),
+
+ // peripheral signals
+ .peri_i(pwr_peri_i)
);
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- ack_pwrdn <= '0;
- pwrup_cause <= Por;
- end else if (cdc_safe) begin
- ack_pwrdn <= slow_ack_pwrdn;
- pwrup_cause <= slow_pwrup_cause;
- end
- end
-
- ////////////////////////////
- /// cdc handling - clk_slow_i
- ////////////////////////////
-
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- slow_wakeup_en <= '0;
- slow_reset_en <= '0;
- slow_main_pdb <= '0;
- slow_io_clk_en <= '0;
- slow_core_clk_en <= '0;
- slow_ack_pwrup <= '0;
- slow_req_pwrdn <= '0;
- end else if (cdc_safe) begin
- slow_wakeup_en <= reg2hw.wakeup_en.q;
- slow_reset_en <= reg2hw.reset_en.q;
- slow_main_pdb <= reg2hw.control.main_pdb.q;
- slow_io_clk_en <= reg2hw.control.io_clk_en.q;
- slow_core_clk_en <= reg2hw.control.core_clk_en.q;
- slow_ack_pwrup <= ack_pwrup;
- slow_req_pwrdn <= req_pwrdn;
- end
- end
-
- // TODO
- // Need to vote on the differential signals to ensure they are stable
- prim_flop_2sync # (
- .Width($bits(pwr_ast_rsp_t))
- ) i_pok_sync (
- .clk_i (clk_slow_i),
- .rst_ni (rst_slow_ni),
- .d (pwr_ast_i),
- .q (slow_ast_q)
- );
-
+ assign hw2reg.cfg_cdc_sync.d = 1'b0;
////////////////////////////
/// Wakup and reset capture
@@ -213,28 +190,7 @@
// scale approximately the same across all domains.
//
// This also implies that these signals must be at least 1 clk_slow pulse long
-
- prim_flop_2sync # (
- .Width(HwRstReqs + WakeUpPeris)
- ) i_slow_ext_req_sync (
- .clk_i (clk_slow_i),
- .rst_ni (rst_slow_ni),
- .d (pwr_peri_i),
- .q (slow_ext_reqs)
- );
-
- assign slow_ext_reqs_masked.wakeups = slow_ext_reqs.wakeups & slow_wakeup_en;
- assign slow_ext_reqs_masked.rstreqs = slow_ext_reqs.rstreqs & slow_reset_en;
-
- prim_flop_2sync # (
- .Width(HwRstReqs + WakeUpPeris)
- ) i_ext_req_sync (
- .clk_i,
- .rst_ni,
- .d (slow_ext_reqs),
- .q (ext_reqs)
- );
-
+ //
// Since resets are not latched inside pwrmgr, there exists a corner case where
// non-always-on reset requests may get wiped out by a graceful low power entry
// It's not clear if this is really an issue at the moment, but something to keep
@@ -244,38 +200,37 @@
// should clear it and when that should happen. If the clearing does not work
// correctly, it is possible for the device to end up in a permanent reset loop,
// and that would be very undesirable.
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- ext_reqs_masked <= '0;
- end else if (cdc_safe) begin
- ext_reqs_masked.wakeups <= ext_reqs.wakeups & reg2hw.wakeup_en;
- ext_reqs_masked.rstreqs <= ext_reqs.rstreqs & reg2hw.reset_en;
- end
- end
+
+ assign slow_ext_reqs_masked.wakeups = slow_ext_reqs.wakeups & slow_wakeup_en;
+ assign slow_ext_reqs_masked.rstreqs = slow_ext_reqs.rstreqs & slow_reset_en;
+
+
+
////////////////////////////
/// clk_slow FSM
////////////////////////////
pwrmgr_slow_fsm i_slow_fsm (
- .clk_i (clk_slow_i),
- .rst_ni (rst_slow_ni),
- .wakeup_i (|slow_ext_reqs_masked.wakeups),
- .reset_req_i (|slow_ext_reqs_masked.rstreqs),
- .ast_i (slow_ast_q),
- .req_pwrup_o (slow_req_pwrup),
- .pwrup_cause_o (slow_pwrup_cause),
- .ack_pwrup_i (slow_ack_pwrup),
- .req_pwrdn_i (slow_req_pwrdn),
- .ack_pwrdn_o (slow_ack_pwrdn),
+ .clk_i (clk_slow_i),
+ .rst_ni (rst_slow_ni),
+ .wakeup_i (|slow_ext_reqs_masked.wakeups),
+ .reset_req_i (|slow_ext_reqs_masked.rstreqs),
+ .ast_i (slow_ast),
+ .req_pwrup_o (slow_req_pwrup),
+ .pwrup_cause_o (slow_pwrup_cause),
+ .pwrup_cause_toggle_o (slow_pwrup_cause_toggle),
+ .ack_pwrup_i (slow_ack_pwrup),
+ .req_pwrdn_i (slow_req_pwrdn),
+ .ack_pwrdn_o (slow_ack_pwrdn),
- .main_pdb_i (slow_main_pdb),
- .io_clk_en_i (slow_io_clk_en),
- .core_clk_en_i (slow_core_clk_en),
+ .main_pdb_i (slow_main_pdb),
+ .io_clk_en_i (slow_io_clk_en),
+ .core_clk_en_i (slow_core_clk_en),
// outputs to AST - These are on the slow clock domain
// TBD - need to check this with partners
- .ast_o (pwr_ast_o)
+ .ast_o (pwr_ast_o)
);
diff --git a/hw/ip/pwrmgr/rtl/pwrmgr_cdc.sv b/hw/ip/pwrmgr/rtl/pwrmgr_cdc.sv
new file mode 100644
index 0000000..5d73a3a
--- /dev/null
+++ b/hw/ip/pwrmgr/rtl/pwrmgr_cdc.sv
@@ -0,0 +1,300 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Power Manager CDC handling
+//
+
+`include "prim_assert.sv"
+
+module pwrmgr_cdc import pwrmgr_pkg::*;
+(
+ // Clocks and resets
+ input clk_slow_i,
+ input clk_i,
+ input rst_slow_ni,
+ input rst_ni,
+
+ // slow domain signals,
+ input slow_req_pwrup_i,
+ input slow_ack_pwrdn_i,
+ input slow_pwrup_cause_toggle_i,
+ input pwrup_cause_e slow_pwrup_cause_i,
+ output pwrmgr_reg_pkg::pwrmgr_reg2hw_wakeup_en_reg_t slow_wakeup_en_o,
+ output pwrmgr_reg_pkg::pwrmgr_reg2hw_reset_en_reg_t slow_reset_en_o,
+ output logic slow_main_pdb_o,
+ output logic slow_io_clk_en_o,
+ output logic slow_core_clk_en_o,
+ output logic slow_req_pwrdn_o,
+ output logic slow_ack_pwrup_o,
+ output pwr_ast_rsp_t slow_ast_o,
+ output pwr_peri_rsp_t slow_ext_reqs_o,
+ input pwr_peri_rsp_t slow_ext_reqs_masked_i,
+
+ // fast domain signals
+ input req_pwrdn_i,
+ input ack_pwrup_i,
+ input cfg_cdc_sync_i,
+ input pwrmgr_reg_pkg::pwrmgr_reg2hw_wakeup_en_reg_t wakeup_en_i,
+ input pwrmgr_reg_pkg::pwrmgr_reg2hw_reset_en_reg_t reset_en_i,
+ input main_pdb_i,
+ input io_clk_en_i,
+ input core_clk_en_i,
+ output logic ack_pwrdn_o,
+ output logic req_pwrup_o,
+ output pwrup_cause_e pwrup_cause_o,
+ output pwr_peri_rsp_t ext_reqs_o,
+ output logic cdc_sync_done_o,
+
+ // peripheral inputs, mixed domains
+ input pwr_peri_rsp_t peri_i,
+
+ // AST inputs, unknown domain
+ input pwr_ast_rsp_t ast_i
+
+);
+
+ ////////////////////////////////
+ // Sync from clk_i to clk_slow_i
+ ////////////////////////////////
+
+ logic slow_cdc_sync;
+ pwr_ast_rsp_t slow_ast_q, slow_ast_q2;
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_req_pwrdn_sync (
+ .clk_i(clk_slow_i),
+ .rst_ni(rst_slow_ni),
+ .d(req_pwrdn_i),
+ .q(slow_req_pwrdn_o)
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_ack_pwrup_sync (
+ .clk_i(clk_slow_i),
+ .rst_ni(rst_slow_ni),
+ .d(ack_pwrup_i),
+ .q(slow_ack_pwrup_o)
+ );
+
+ prim_pulse_sync i_slow_cdc_sync (
+ .clk_src_i(clk_i),
+ .rst_src_ni(rst_ni),
+ .src_pulse_i(cfg_cdc_sync_i),
+ .clk_dst_i(clk_slow_i),
+ .rst_dst_ni(rst_slow_ni),
+ .dst_pulse_o(slow_cdc_sync)
+ );
+
+ // Even though this is multi-bit, the bits are individual request lines.
+ // So there is no general concern about recombining as there is
+ // no intent to use them in a related manner.
+ prim_flop_2sync # (
+ .Width(HwRstReqs + WakeUpPeris)
+ ) i_slow_ext_req_sync (
+ .clk_i (clk_slow_i),
+ .rst_ni (rst_slow_ni),
+ .d (peri_i),
+ .q (slow_ext_reqs_o)
+ );
+
+
+ // Some of the AST signals are multi-bits themselves (such as clk_val)
+ // thus they need to be delayed one more stage to check for stability
+ prim_flop_2sync # (
+ .Width($bits(pwr_ast_rsp_t)),
+ .ResetValue(PWR_AST_RSP_SYNC_DEFAULT)
+ ) i_ast_sync (
+ .clk_i (clk_slow_i),
+ .rst_ni (rst_slow_ni),
+ .d (ast_i),
+ .q (slow_ast_q)
+ );
+
+ always_ff @(posedge clk_slow_i or negedge rst_slow_ni) begin
+ if (!rst_slow_ni) begin
+ slow_ast_q2 <= PWR_AST_RSP_SYNC_DEFAULT;
+ end else begin
+ slow_ast_q2 <= slow_ast_q;
+ end
+ end
+
+ // if possible, we should simulate below with random delays through
+ // flop_2sync
+ always_ff @(posedge clk_slow_i or negedge rst_slow_ni) begin
+ if (!rst_slow_ni) begin
+ slow_ast_o <= PWR_AST_RSP_SYNC_DEFAULT;
+ end else if (slow_ast_q2 == slow_ast_q) begin
+ // Output only updates whenever sync and delayed outputs both agree.
+ // If there are delays in sync, this will result in a 1 cycle difference
+ // and the output will hold the previous value
+ slow_ast_o <= slow_ast_q2;
+ end
+ end
+
+ // only register configurations can be sync'd using slow_cdc_sync
+ always_ff @(posedge clk_slow_i or negedge rst_slow_ni) begin
+ if (!rst_slow_ni) begin
+ slow_wakeup_en_o <= '0;
+ slow_reset_en_o <= '0;
+ slow_main_pdb_o <= '0;
+ slow_io_clk_en_o <= '0;
+ slow_core_clk_en_o <= '0;
+ end else if (slow_cdc_sync) begin
+ slow_wakeup_en_o <= wakeup_en_i;
+ slow_reset_en_o <= reset_en_i;
+ slow_main_pdb_o <= main_pdb_i;
+ slow_io_clk_en_o <= io_clk_en_i;
+ slow_core_clk_en_o <= core_clk_en_i;
+ end
+ end
+
+ ////////////////////////////////
+ // Sync from clk_slow_i to clk_i
+ ////////////////////////////////
+
+ logic pwrup_cause_toggle_q, pwrup_cause_toggle_q2;
+ logic pwrup_cause_chg;
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_req_pwrup_sync (
+ .clk_i,
+ .rst_ni,
+ .d(slow_req_pwrup_i),
+ .q(req_pwrup_o)
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_ack_pwrdn_sync (
+ .clk_i,
+ .rst_ni,
+ .d(slow_ack_pwrdn_i),
+ .q(ack_pwrdn_o)
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_pwrup_chg_sync (
+ .clk_i,
+ .rst_ni,
+ .d(slow_pwrup_cause_toggle_i),
+ .q(pwrup_cause_toggle_q)
+ );
+
+ prim_pulse_sync i_scdc_sync (
+ .clk_src_i(clk_slow_i),
+ .rst_src_ni(rst_slow_ni),
+ .src_pulse_i(slow_cdc_sync),
+ .clk_dst_i(clk_i),
+ .rst_dst_ni(rst_ni),
+ .dst_pulse_o(cdc_sync_done_o)
+ );
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ pwrup_cause_toggle_q2 <= 1'b0;
+ end else begin
+ pwrup_cause_toggle_q2 <= pwrup_cause_toggle_q;
+ end
+ end
+
+ assign pwrup_cause_chg = pwrup_cause_toggle_q2 ^ pwrup_cause_toggle_q;
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ pwrup_cause_o <= Por;
+ end else if (pwrup_cause_chg) begin
+ pwrup_cause_o <= slow_pwrup_cause_i;
+ end
+ end
+
+ prim_flop_2sync # (
+ .Width(HwRstReqs + WakeUpPeris)
+ ) i_ext_req_sync (
+ .clk_i,
+ .rst_ni,
+ .d (slow_ext_reqs_masked_i),
+ .q (ext_reqs_o)
+ );
+
+
+endmodule
+
+
+// An alternative solution relying on finding slow clock edges
+// Keep it around just in case
+
+/*
+ // finds a clk_slow edge in clk domain to know when it is safe to sync over
+ // this signal is only safe to use within the pwrmgr module when the source
+ // and destination clock domains are both clear
+ logic cdc_safe;
+
+ // pwrup is synced directly as it acts as a start signal to the pulse module
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_pwrup_sync (
+ .clk_i,
+ .rst_ni,
+ .d(slow_req_pwrup),
+ .q(req_pwrup)
+ );
+
+ pwrmgr_cdc_pulse i_cdc_pulse (
+ .clk_slow_i,
+ .clk_i,
+ .rst_ni,
+ .start_i(req_pwrup),
+ .stop_i(req_pwrdn),
+ .pulse_o(cdc_safe)
+ );
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ ack_pwrdn <= '0;
+ pwrup_cause <= Por;
+ end else if (cdc_safe) begin
+ ack_pwrdn <= slow_ack_pwrdn;
+ pwrup_cause <= slow_pwrup_cause;
+ end
+ end
+
+ ////////////////////////////
+ /// cdc handling - clk_slow_i
+ ////////////////////////////
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ slow_wakeup_en <= '0;
+ slow_reset_en <= '0;
+ slow_main_pdb <= '0;
+ slow_io_clk_en <= '0;
+ slow_core_clk_en <= '0;
+ slow_ack_pwrup <= '0;
+ slow_req_pwrdn <= '0;
+ end else if (cdc_safe) begin
+ slow_wakeup_en <= reg2hw.wakeup_en.q;
+ slow_reset_en <= reg2hw.reset_en.q;
+ slow_main_pdb <= reg2hw.control.main_pdb.q;
+ slow_io_clk_en <= reg2hw.control.io_clk_en.q;
+ slow_core_clk_en <= reg2hw.control.core_clk_en.q;
+ slow_ack_pwrup <= ack_pwrup;
+ slow_req_pwrdn <= req_pwrdn;
+ end
+ end
+
+ // TODO
+ // Need to vote on the differential signals to ensure they are stable
+ prim_flop_2sync # (
+ .Width($bits(pwr_ast_rsp_t))
+ ) i_pok_sync (
+ .clk_i (clk_slow_i),
+ .rst_ni (rst_slow_ni),
+ .d (pwr_ast_i),
+ .q (slow_ast_q)
+ );
+*/
diff --git a/hw/ip/pwrmgr/rtl/pwrmgr_cdc_pulse.sv b/hw/ip/pwrmgr/rtl/pwrmgr_cdc_pulse.sv
index dad86e1..e8391fc 100644
--- a/hw/ip/pwrmgr/rtl/pwrmgr_cdc_pulse.sv
+++ b/hw/ip/pwrmgr/rtl/pwrmgr_cdc_pulse.sv
@@ -41,7 +41,7 @@
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
valid <= 1'b0;
- end else if (valid & stop_i) begin
+ end else if (valid && stop_i) begin
valid <= 1'b0;
end else if (!valid && toggle && start_i) begin
valid <= 1'b1;
diff --git a/hw/ip/pwrmgr/rtl/pwrmgr_fsm.sv b/hw/ip/pwrmgr/rtl/pwrmgr_fsm.sv
index a50a123..0c263bb 100644
--- a/hw/ip/pwrmgr/rtl/pwrmgr_fsm.sv
+++ b/hw/ip/pwrmgr/rtl/pwrmgr_fsm.sv
@@ -8,45 +8,45 @@
`include "prim_assert.sv"
module pwrmgr_fsm import pwrmgr_pkg::*; (
- input clk_i,
- input rst_ni,
+ input clk_i,
+ input rst_ni,
- // interface with slow_fsm
- input req_pwrup_i,
- input pwrup_cause_e pwrup_cause_i,
- output logic ack_pwrup_o,
- output logic req_pwrdn_o,
- input ack_pwrdn_i,
- input low_power_entry_i,
- input main_pdb_i,
- input reset_req_i,
+ // interface with slow_fsm
+ input req_pwrup_i,
+ input pwrup_cause_e pwrup_cause_i,
+ output logic ack_pwrup_o,
+ output logic req_pwrdn_o,
+ input ack_pwrdn_i,
+ input low_power_entry_i,
+ input main_pdb_i,
+ input reset_req_i,
- // consumed in pwrmgr
- output logic wkup_o, // generate wake interrupt
- output logic wkup_record_o, // enable wakeup recording
- output logic fall_through_o,
- output logic abort_o,
- output logic clr_cfg_lock_o,
+ // consumed in pwrmgr
+ output logic wkup_o, // generate wake interrupt
+ output logic wkup_record_o, // enable wakeup recording
+ output logic fall_through_o,
+ output logic abort_o,
+ output logic clr_cfg_lock_o,
- // rstmgr
- output pwr_rst_req_t pwr_rst_o,
- input pwr_rst_rsp_t pwr_rst_i,
+ // rstmgr
+ output pwr_rst_req_t pwr_rst_o,
+ input pwr_rst_rsp_t pwr_rst_i,
- // clkmgr
- output logic ips_clk_en_o,
+ // clkmgr
+ output logic ips_clk_en_o,
- // otp
- output logic otp_init_o,
- input otp_done_i,
- input otp_idle_i,
+ // otp
+ output logic otp_init_o,
+ input otp_done_i,
+ input otp_idle_i,
- // lc
- output logic lc_init_o,
- input lc_done_i,
- input lc_idle_i,
+ // lc
+ output logic lc_init_o,
+ input lc_done_i,
+ input lc_idle_i,
- // flash
- input flash_idle_i
+ // flash
+ input flash_idle_i
);
// state enum
@@ -97,7 +97,7 @@
logic otp_init;
logic lc_init;
- assign pdb_rsts_asserted = pwr_rst_i.rst_lc_src_n[PowerDomains-1:1] == '0 &&
+ assign pdb_rsts_asserted = pwr_rst_i.rst_lc_src_n[PowerDomains-1:1] == '0 &
pwr_rst_i.rst_sys_src_n[PowerDomains-1:1] == '0;
assign all_rsts_asserted = pwr_rst_i.rst_lc_src_n == '0 &&
diff --git a/hw/ip/pwrmgr/rtl/pwrmgr_pkg.sv b/hw/ip/pwrmgr/rtl/pwrmgr_pkg.sv
index 1db70ea..17e9cf3 100644
--- a/hw/ip/pwrmgr/rtl/pwrmgr_pkg.sv
+++ b/hw/ip/pwrmgr/rtl/pwrmgr_pkg.sv
@@ -37,6 +37,13 @@
main_pok: 1'b1
};
+ parameter pwr_ast_rsp_t PWR_AST_RSP_SYNC_DEFAULT = '{
+ slow_clk_val: 2'b01,
+ core_clk_val: 2'b01,
+ io_clk_val: 2'b10,
+ main_pok: 1'b0
+ };
+
// pwrmgr to rstmgr
typedef struct packed {
logic [PowerDomains-1:0] lc_rst_req;
diff --git a/hw/ip/pwrmgr/rtl/pwrmgr_reg_pkg.sv b/hw/ip/pwrmgr/rtl/pwrmgr_reg_pkg.sv
index c31e224..54a03f2 100644
--- a/hw/ip/pwrmgr/rtl/pwrmgr_reg_pkg.sv
+++ b/hw/ip/pwrmgr/rtl/pwrmgr_reg_pkg.sv
@@ -23,6 +23,11 @@
} pwrmgr_reg2hw_intr_test_reg_t;
typedef struct packed {
+ logic q;
+ logic qe;
+ } pwrmgr_reg2hw_cfg_cdc_sync_reg_t;
+
+ typedef struct packed {
struct packed {
logic q;
} low_power_hint;
@@ -72,6 +77,11 @@
typedef struct packed {
logic d;
+ logic de;
+ } pwrmgr_hw2reg_cfg_cdc_sync_reg_t;
+
+ typedef struct packed {
+ logic d;
} pwrmgr_hw2reg_ctrl_cfg_regwen_reg_t;
typedef struct packed {
@@ -98,9 +108,10 @@
// Register to internal design logic //
///////////////////////////////////////
typedef struct packed {
- pwrmgr_reg2hw_intr_state_reg_t intr_state; // [47:47]
- pwrmgr_reg2hw_intr_enable_reg_t intr_enable; // [46:46]
- pwrmgr_reg2hw_intr_test_reg_t intr_test; // [45:44]
+ pwrmgr_reg2hw_intr_state_reg_t intr_state; // [49:49]
+ pwrmgr_reg2hw_intr_enable_reg_t intr_enable; // [48:48]
+ pwrmgr_reg2hw_intr_test_reg_t intr_test; // [47:46]
+ pwrmgr_reg2hw_cfg_cdc_sync_reg_t cfg_cdc_sync; // [45:44]
pwrmgr_reg2hw_control_reg_t control; // [43:40]
pwrmgr_reg2hw_wakeup_en_reg_t wakeup_en; // [39:24]
pwrmgr_reg2hw_reset_en_reg_t reset_en; // [23:22]
@@ -112,7 +123,8 @@
// Internal design logic to register //
///////////////////////////////////////
typedef struct packed {
- pwrmgr_hw2reg_intr_state_reg_t intr_state; // [22:22]
+ pwrmgr_hw2reg_intr_state_reg_t intr_state; // [24:24]
+ pwrmgr_hw2reg_cfg_cdc_sync_reg_t cfg_cdc_sync; // [23:22]
pwrmgr_hw2reg_ctrl_cfg_regwen_reg_t ctrl_cfg_regwen; // [21:22]
pwrmgr_hw2reg_control_reg_t control; // [21:18]
pwrmgr_hw2reg_wake_info_reg_t wake_info; // [17:-3]
@@ -122,16 +134,17 @@
parameter logic [5:0] PWRMGR_INTR_STATE_OFFSET = 6'h 0;
parameter logic [5:0] PWRMGR_INTR_ENABLE_OFFSET = 6'h 4;
parameter logic [5:0] PWRMGR_INTR_TEST_OFFSET = 6'h 8;
- parameter logic [5:0] PWRMGR_CTRL_CFG_REGWEN_OFFSET = 6'h c;
- parameter logic [5:0] PWRMGR_CONTROL_OFFSET = 6'h 10;
- parameter logic [5:0] PWRMGR_WAKEUP_EN_REGWEN_OFFSET = 6'h 14;
- parameter logic [5:0] PWRMGR_WAKEUP_EN_OFFSET = 6'h 18;
- parameter logic [5:0] PWRMGR_WAKE_STATUS_OFFSET = 6'h 1c;
- parameter logic [5:0] PWRMGR_RESET_EN_REGWEN_OFFSET = 6'h 20;
- parameter logic [5:0] PWRMGR_RESET_EN_OFFSET = 6'h 24;
- parameter logic [5:0] PWRMGR_RESET_STATUS_OFFSET = 6'h 28;
- parameter logic [5:0] PWRMGR_WAKE_INFO_CAPTURE_DIS_OFFSET = 6'h 2c;
- parameter logic [5:0] PWRMGR_WAKE_INFO_OFFSET = 6'h 30;
+ parameter logic [5:0] PWRMGR_CFG_CDC_SYNC_OFFSET = 6'h c;
+ parameter logic [5:0] PWRMGR_CTRL_CFG_REGWEN_OFFSET = 6'h 10;
+ parameter logic [5:0] PWRMGR_CONTROL_OFFSET = 6'h 14;
+ parameter logic [5:0] PWRMGR_WAKEUP_EN_REGWEN_OFFSET = 6'h 18;
+ parameter logic [5:0] PWRMGR_WAKEUP_EN_OFFSET = 6'h 1c;
+ parameter logic [5:0] PWRMGR_WAKE_STATUS_OFFSET = 6'h 20;
+ parameter logic [5:0] PWRMGR_RESET_EN_REGWEN_OFFSET = 6'h 24;
+ parameter logic [5:0] PWRMGR_RESET_EN_OFFSET = 6'h 28;
+ parameter logic [5:0] PWRMGR_RESET_STATUS_OFFSET = 6'h 2c;
+ parameter logic [5:0] PWRMGR_WAKE_INFO_CAPTURE_DIS_OFFSET = 6'h 30;
+ parameter logic [5:0] PWRMGR_WAKE_INFO_OFFSET = 6'h 34;
// Register Index
@@ -139,6 +152,7 @@
PWRMGR_INTR_STATE,
PWRMGR_INTR_ENABLE,
PWRMGR_INTR_TEST,
+ PWRMGR_CFG_CDC_SYNC,
PWRMGR_CTRL_CFG_REGWEN,
PWRMGR_CONTROL,
PWRMGR_WAKEUP_EN_REGWEN,
@@ -152,20 +166,21 @@
} pwrmgr_id_e;
// Register width information to check illegal writes
- parameter logic [3:0] PWRMGR_PERMIT [13] = '{
+ parameter logic [3:0] PWRMGR_PERMIT [14] = '{
4'b 0001, // index[ 0] PWRMGR_INTR_STATE
4'b 0001, // index[ 1] PWRMGR_INTR_ENABLE
4'b 0001, // index[ 2] PWRMGR_INTR_TEST
- 4'b 0001, // index[ 3] PWRMGR_CTRL_CFG_REGWEN
- 4'b 0001, // index[ 4] PWRMGR_CONTROL
- 4'b 0001, // index[ 5] PWRMGR_WAKEUP_EN_REGWEN
- 4'b 0011, // index[ 6] PWRMGR_WAKEUP_EN
- 4'b 0011, // index[ 7] PWRMGR_WAKE_STATUS
- 4'b 0001, // index[ 8] PWRMGR_RESET_EN_REGWEN
- 4'b 0001, // index[ 9] PWRMGR_RESET_EN
- 4'b 0001, // index[10] PWRMGR_RESET_STATUS
- 4'b 0001, // index[11] PWRMGR_WAKE_INFO_CAPTURE_DIS
- 4'b 0111 // index[12] PWRMGR_WAKE_INFO
+ 4'b 0001, // index[ 3] PWRMGR_CFG_CDC_SYNC
+ 4'b 0001, // index[ 4] PWRMGR_CTRL_CFG_REGWEN
+ 4'b 0001, // index[ 5] PWRMGR_CONTROL
+ 4'b 0001, // index[ 6] PWRMGR_WAKEUP_EN_REGWEN
+ 4'b 0011, // index[ 7] PWRMGR_WAKEUP_EN
+ 4'b 0011, // index[ 8] PWRMGR_WAKE_STATUS
+ 4'b 0001, // index[ 9] PWRMGR_RESET_EN_REGWEN
+ 4'b 0001, // index[10] PWRMGR_RESET_EN
+ 4'b 0001, // index[11] PWRMGR_RESET_STATUS
+ 4'b 0001, // index[12] PWRMGR_WAKE_INFO_CAPTURE_DIS
+ 4'b 0111 // index[13] PWRMGR_WAKE_INFO
};
endpackage
diff --git a/hw/ip/pwrmgr/rtl/pwrmgr_reg_top.sv b/hw/ip/pwrmgr/rtl/pwrmgr_reg_top.sv
index 4e567f0..7a63697 100644
--- a/hw/ip/pwrmgr/rtl/pwrmgr_reg_top.sv
+++ b/hw/ip/pwrmgr/rtl/pwrmgr_reg_top.sv
@@ -79,6 +79,8 @@
logic intr_enable_we;
logic intr_test_wd;
logic intr_test_we;
+ logic cfg_cdc_sync_wd;
+ logic cfg_cdc_sync_we;
logic ctrl_cfg_regwen_qs;
logic ctrl_cfg_regwen_wd;
logic ctrl_cfg_regwen_we;
@@ -196,6 +198,32 @@
);
+ // R[cfg_cdc_sync]: V(False)
+
+ prim_subreg #(
+ .DW (1),
+ .SWACCESS("WO"),
+ .RESVAL (1'h0)
+ ) u_cfg_cdc_sync (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (cfg_cdc_sync_we),
+ .wd (cfg_cdc_sync_wd),
+
+ // from internal hardware
+ .de (hw2reg.cfg_cdc_sync.de),
+ .d (hw2reg.cfg_cdc_sync.d ),
+
+ // to internal hardware
+ .qe (reg2hw.cfg_cdc_sync.qe),
+ .q (reg2hw.cfg_cdc_sync.q ),
+
+ .qs ()
+ );
+
+
// R[ctrl_cfg_regwen]: V(True)
prim_subreg_ext #(
@@ -514,22 +542,23 @@
- logic [12:0] addr_hit;
+ logic [13:0] addr_hit;
always_comb begin
addr_hit = '0;
addr_hit[ 0] = (reg_addr == PWRMGR_INTR_STATE_OFFSET);
addr_hit[ 1] = (reg_addr == PWRMGR_INTR_ENABLE_OFFSET);
addr_hit[ 2] = (reg_addr == PWRMGR_INTR_TEST_OFFSET);
- addr_hit[ 3] = (reg_addr == PWRMGR_CTRL_CFG_REGWEN_OFFSET);
- addr_hit[ 4] = (reg_addr == PWRMGR_CONTROL_OFFSET);
- addr_hit[ 5] = (reg_addr == PWRMGR_WAKEUP_EN_REGWEN_OFFSET);
- addr_hit[ 6] = (reg_addr == PWRMGR_WAKEUP_EN_OFFSET);
- addr_hit[ 7] = (reg_addr == PWRMGR_WAKE_STATUS_OFFSET);
- addr_hit[ 8] = (reg_addr == PWRMGR_RESET_EN_REGWEN_OFFSET);
- addr_hit[ 9] = (reg_addr == PWRMGR_RESET_EN_OFFSET);
- addr_hit[10] = (reg_addr == PWRMGR_RESET_STATUS_OFFSET);
- addr_hit[11] = (reg_addr == PWRMGR_WAKE_INFO_CAPTURE_DIS_OFFSET);
- addr_hit[12] = (reg_addr == PWRMGR_WAKE_INFO_OFFSET);
+ addr_hit[ 3] = (reg_addr == PWRMGR_CFG_CDC_SYNC_OFFSET);
+ addr_hit[ 4] = (reg_addr == PWRMGR_CTRL_CFG_REGWEN_OFFSET);
+ addr_hit[ 5] = (reg_addr == PWRMGR_CONTROL_OFFSET);
+ addr_hit[ 6] = (reg_addr == PWRMGR_WAKEUP_EN_REGWEN_OFFSET);
+ addr_hit[ 7] = (reg_addr == PWRMGR_WAKEUP_EN_OFFSET);
+ addr_hit[ 8] = (reg_addr == PWRMGR_WAKE_STATUS_OFFSET);
+ addr_hit[ 9] = (reg_addr == PWRMGR_RESET_EN_REGWEN_OFFSET);
+ addr_hit[10] = (reg_addr == PWRMGR_RESET_EN_OFFSET);
+ addr_hit[11] = (reg_addr == PWRMGR_RESET_STATUS_OFFSET);
+ addr_hit[12] = (reg_addr == PWRMGR_WAKE_INFO_CAPTURE_DIS_OFFSET);
+ addr_hit[13] = (reg_addr == PWRMGR_WAKE_INFO_OFFSET);
end
assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
@@ -550,6 +579,7 @@
if (addr_hit[10] && reg_we && (PWRMGR_PERMIT[10] != (PWRMGR_PERMIT[10] & reg_be))) wr_err = 1'b1 ;
if (addr_hit[11] && reg_we && (PWRMGR_PERMIT[11] != (PWRMGR_PERMIT[11] & reg_be))) wr_err = 1'b1 ;
if (addr_hit[12] && reg_we && (PWRMGR_PERMIT[12] != (PWRMGR_PERMIT[12] & reg_be))) wr_err = 1'b1 ;
+ if (addr_hit[13] && reg_we && (PWRMGR_PERMIT[13] != (PWRMGR_PERMIT[13] & reg_be))) wr_err = 1'b1 ;
end
assign intr_state_we = addr_hit[0] & reg_we & ~wr_err;
@@ -561,50 +591,53 @@
assign intr_test_we = addr_hit[2] & reg_we & ~wr_err;
assign intr_test_wd = reg_wdata[0];
- assign ctrl_cfg_regwen_we = addr_hit[3] & reg_we & ~wr_err;
- assign ctrl_cfg_regwen_wd = reg_wdata[0];
- assign ctrl_cfg_regwen_re = addr_hit[3] && reg_re;
+ assign cfg_cdc_sync_we = addr_hit[3] & reg_we & ~wr_err;
+ assign cfg_cdc_sync_wd = reg_wdata[0];
- assign control_low_power_hint_we = addr_hit[4] & reg_we & ~wr_err;
+ assign ctrl_cfg_regwen_we = addr_hit[4] & reg_we & ~wr_err;
+ assign ctrl_cfg_regwen_wd = reg_wdata[0];
+ assign ctrl_cfg_regwen_re = addr_hit[4] && reg_re;
+
+ assign control_low_power_hint_we = addr_hit[5] & reg_we & ~wr_err;
assign control_low_power_hint_wd = reg_wdata[0];
- assign control_core_clk_en_we = addr_hit[4] & reg_we & ~wr_err;
+ assign control_core_clk_en_we = addr_hit[5] & reg_we & ~wr_err;
assign control_core_clk_en_wd = reg_wdata[4];
- assign control_io_clk_en_we = addr_hit[4] & reg_we & ~wr_err;
+ assign control_io_clk_en_we = addr_hit[5] & reg_we & ~wr_err;
assign control_io_clk_en_wd = reg_wdata[5];
- assign control_main_pdb_we = addr_hit[4] & reg_we & ~wr_err;
+ assign control_main_pdb_we = addr_hit[5] & reg_we & ~wr_err;
assign control_main_pdb_wd = reg_wdata[6];
- assign wakeup_en_regwen_we = addr_hit[5] & reg_we & ~wr_err;
+ assign wakeup_en_regwen_we = addr_hit[6] & reg_we & ~wr_err;
assign wakeup_en_regwen_wd = reg_wdata[0];
- assign wakeup_en_we = addr_hit[6] & reg_we & ~wr_err;
+ assign wakeup_en_we = addr_hit[7] & reg_we & ~wr_err;
assign wakeup_en_wd = reg_wdata[15:0];
- assign reset_en_regwen_we = addr_hit[8] & reg_we & ~wr_err;
+ assign reset_en_regwen_we = addr_hit[9] & reg_we & ~wr_err;
assign reset_en_regwen_wd = reg_wdata[0];
- assign reset_en_we = addr_hit[9] & reg_we & ~wr_err;
+ assign reset_en_we = addr_hit[10] & reg_we & ~wr_err;
assign reset_en_wd = reg_wdata[1:0];
- assign wake_info_capture_dis_we = addr_hit[11] & reg_we & ~wr_err;
+ assign wake_info_capture_dis_we = addr_hit[12] & reg_we & ~wr_err;
assign wake_info_capture_dis_wd = reg_wdata[0];
- assign wake_info_reasons_we = addr_hit[12] & reg_we & ~wr_err;
+ assign wake_info_reasons_we = addr_hit[13] & reg_we & ~wr_err;
assign wake_info_reasons_wd = reg_wdata[15:0];
- assign wake_info_reasons_re = addr_hit[12] && reg_re;
+ assign wake_info_reasons_re = addr_hit[13] && reg_re;
- assign wake_info_fall_through_we = addr_hit[12] & reg_we & ~wr_err;
+ assign wake_info_fall_through_we = addr_hit[13] & reg_we & ~wr_err;
assign wake_info_fall_through_wd = reg_wdata[16];
- assign wake_info_fall_through_re = addr_hit[12] && reg_re;
+ assign wake_info_fall_through_re = addr_hit[13] && reg_re;
- assign wake_info_abort_we = addr_hit[12] & reg_we & ~wr_err;
+ assign wake_info_abort_we = addr_hit[13] & reg_we & ~wr_err;
assign wake_info_abort_wd = reg_wdata[17];
- assign wake_info_abort_re = addr_hit[12] && reg_re;
+ assign wake_info_abort_re = addr_hit[13] && reg_re;
// Read data return
always_comb begin
@@ -623,45 +656,49 @@
end
addr_hit[3]: begin
- reg_rdata_next[0] = ctrl_cfg_regwen_qs;
+ reg_rdata_next[0] = '0;
end
addr_hit[4]: begin
+ reg_rdata_next[0] = ctrl_cfg_regwen_qs;
+ end
+
+ addr_hit[5]: begin
reg_rdata_next[0] = control_low_power_hint_qs;
reg_rdata_next[4] = control_core_clk_en_qs;
reg_rdata_next[5] = control_io_clk_en_qs;
reg_rdata_next[6] = control_main_pdb_qs;
end
- addr_hit[5]: begin
+ addr_hit[6]: begin
reg_rdata_next[0] = wakeup_en_regwen_qs;
end
- addr_hit[6]: begin
+ addr_hit[7]: begin
reg_rdata_next[15:0] = wakeup_en_qs;
end
- addr_hit[7]: begin
+ addr_hit[8]: begin
reg_rdata_next[15:0] = wake_status_qs;
end
- addr_hit[8]: begin
+ addr_hit[9]: begin
reg_rdata_next[0] = reset_en_regwen_qs;
end
- addr_hit[9]: begin
+ addr_hit[10]: begin
reg_rdata_next[1:0] = reset_en_qs;
end
- addr_hit[10]: begin
+ addr_hit[11]: begin
reg_rdata_next[1:0] = reset_status_qs;
end
- addr_hit[11]: begin
+ addr_hit[12]: begin
reg_rdata_next[0] = wake_info_capture_dis_qs;
end
- addr_hit[12]: begin
+ addr_hit[13]: begin
reg_rdata_next[15:0] = wake_info_reasons_qs;
reg_rdata_next[16] = wake_info_fall_through_qs;
reg_rdata_next[17] = wake_info_abort_qs;
diff --git a/hw/ip/pwrmgr/rtl/pwrmgr_slow_fsm.sv b/hw/ip/pwrmgr/rtl/pwrmgr_slow_fsm.sv
index be2e78c..c080250 100644
--- a/hw/ip/pwrmgr/rtl/pwrmgr_slow_fsm.sv
+++ b/hw/ip/pwrmgr/rtl/pwrmgr_slow_fsm.sv
@@ -17,6 +17,7 @@
// interface with fast fsm
output logic req_pwrup_o,
+ output logic pwrup_cause_toggle_o,
output pwrup_cause_e pwrup_cause_o,
input ack_pwrup_i,
input req_pwrdn_i,
@@ -47,6 +48,7 @@
state_e state_q, state_d;
pwrup_cause_e cause_q, cause_d;
+ logic cause_toggle_q, cause_toggle_d;
// All power signals and signals going to analog logic are flopped to avoid transitioanl glitches
logic pdb_q, pdb_d;
@@ -54,6 +56,7 @@
logic core_clk_en_q, core_clk_en_d;
logic io_clk_en_q, io_clk_en_d;
+
logic all_clks_valid;
logic all_clks_invalid;
@@ -65,32 +68,35 @@
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
- state_q <= StReset;
- cause_q <= Por;
- pdb_q <= 1'b0;
- pwr_clamp_q <= 1'b1;
- core_clk_en_q <= 1'b0;
- io_clk_en_q <= 1'b0;
+ state_q <= StReset;
+ cause_q <= Por;
+ cause_toggle_q <= 1'b0;
+ pdb_q <= 1'b0;
+ pwr_clamp_q <= 1'b1;
+ core_clk_en_q <= 1'b0;
+ io_clk_en_q <= 1'b0;
end else begin
- state_q <= state_d;
- cause_q <= cause_d;
- pdb_q <= pdb_d;
- pwr_clamp_q <= pwr_clamp_d;
- core_clk_en_q <= core_clk_en_d;
- io_clk_en_q <= io_clk_en_d;
+ state_q <= state_d;
+ cause_q <= cause_d;
+ cause_toggle_q <= cause_toggle_d;
+ pdb_q <= pdb_d;
+ pwr_clamp_q <= pwr_clamp_d;
+ core_clk_en_q <= core_clk_en_d;
+ io_clk_en_q <= io_clk_en_d;
end
end
always_comb begin
- state_d = state_q;
- cause_d = cause_q;
- pdb_d = pdb_q;
- pwr_clamp_d = pwr_clamp_q;
- core_clk_en_d = core_clk_en_q;
- io_clk_en_d = io_clk_en_q;
+ state_d = state_q;
+ cause_d = cause_q;
+ pdb_d = pdb_q;
+ cause_toggle_d = cause_toggle_q;
+ pwr_clamp_d = pwr_clamp_q;
+ core_clk_en_d = core_clk_en_q;
+ io_clk_en_d = io_clk_en_q;
- req_pwrup_o = 1'b0;
- ack_pwrdn_o = 1'b0;
+ req_pwrup_o = 1'b0;
+ ack_pwrdn_o = 1'b0;
unique case(state_q)
@@ -104,6 +110,7 @@
// different
if (wakeup_i || reset_req_i) begin
state_d = StMainPowerOn;
+ cause_toggle_d = ~cause_toggle_q;
cause_d = reset_req_i ? Reset : Wake;
end
end
@@ -183,6 +190,7 @@
assign pwrup_cause_o = cause_q;
+ assign pwrup_cause_toggle_o = cause_toggle_q;
assign ast_o.core_clk_en = core_clk_en_q;
assign ast_o.io_clk_en = io_clk_en_q;