Skip to content

Commit

Permalink
[pwrmgr] Take external SoC reset into account in FSM
Browse files Browse the repository at this point in the history
1. Internally generated reset request passed to SoC.
2. Create a sticky assertion internally to log request.
   Sticky flag cleared only upon external reset deassertion.
3. SoC transfers this request to platform to assert external reset.
4. External SoC reset deasserts after some time.
5. Pwrmgr stays in FastPwrStateRstWait state until the external SoC
   reset deasserts.
6. Boot / reset sequence continues.
7. Also fixes the external reset signal glitch filter to use the por
   reset. This is required to make sure that the external reset state
   does not self-reset once asserted and faithfully forwards that state
   to pwrmgr.
8. Added some debug visibility signals for pwrmgr.
9. Added temporary reset loop back path in pwrmgr TB to translate
   internal reset req from OT --> ext reset from SoC to OT.  Needs a
   proper fix in testbench (issue #22710).

Signed-off-by: Neeraj Upasani <[email protected]>
  • Loading branch information
Neeraj Upasani authored and andreaskurth committed Apr 19, 2024
1 parent e65178a commit d4aa482
Show file tree
Hide file tree
Showing 23 changed files with 386 additions and 63 deletions.
14 changes: 14 additions & 0 deletions hw/ip/pwrmgr/data/pwrmgr.hjson.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@
],

inter_signal_list: [
{ struct: "pwr_boot_status",
type: "uni",
name: "boot_status",
act: "req",
package: "pwrmgr_pkg",
},
{ struct: "pwr_ast",
type: "req_rsp",
name: "pwr_ast",
Expand Down Expand Up @@ -223,6 +229,14 @@

% endfor

{ name: "PwrFsmWaitForExtRst",
desc: "Wait for external reset to complete",
type: "bit",
default: "0",
local: "false",
expose: "true"
},

{ name: "NumRstReqs",
desc: "Number of peripheral reset requets",
type: "int",
Expand Down
5 changes: 4 additions & 1 deletion hw/ip/pwrmgr/dv/tb.sv
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module tb;
wire clk_slow, rst_slow_n;
wire devmode;
wire [NUM_MAX_INTERRUPTS-1:0] interrupts;
wire int_reset_req;

// interfaces
clk_rst_if clk_rst_if (
Expand Down Expand Up @@ -49,6 +50,7 @@ module tb;
);

assign interrupts[0] = pwrmgr_if.intr_wakeup;
assign int_reset_req = tb.dut.internal_reset_req ;

pwrmgr_if pwrmgr_if (
.clk,
Expand Down Expand Up @@ -97,7 +99,8 @@ module tb;

.fetch_en_o(pwrmgr_if.fetch_en),
.wakeups_i (pwrmgr_if.wakeups_i),
.rstreqs_i (pwrmgr_if.rstreqs_i),
// TOOD(#22710): properly cooperate with `pwrmgr_if.rstreqs_i[1]`
.rstreqs_i ({int_reset_req, pwrmgr_if.rstreqs_i[0]}),
.ndmreset_req_i(pwrmgr_if.cpu_i.ndmreset_req),

.lc_dft_en_i (pwrmgr_if.lc_dft_en),
Expand Down
1 change: 1 addition & 0 deletions hw/ip/pwrmgr/pwrmgr_pkg.core
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ filesets:
files_rtl:
depend:
- lowrisc:ip:pwrmgr_reg
- lowrisc:ip:rom_ctrl_pkg
files:
- rtl/pwrmgr_pkg.sv
file_type: systemVerilogSource
Expand Down
49 changes: 43 additions & 6 deletions hw/ip/pwrmgr/rtl/pwrmgr.sv
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ module pwrmgr
import pwrmgr_pkg::*;
import pwrmgr_reg_pkg::*;
#(
parameter logic [NumAlerts-1:0] AlertAsyncOn = {NumAlerts{1'b1}}
parameter logic [NumAlerts-1:0] AlertAsyncOn = {NumAlerts{1'b1}},
parameter bit PwrFsmWaitForExtRst = 0
) (
// Clocks and resets
input clk_slow_i,
Expand Down Expand Up @@ -59,12 +60,13 @@ module pwrmgr
input pwr_cpu_t pwr_cpu_i,
// SEC_CM: LC_CTRL.INTERSIG.MUBI
output lc_ctrl_pkg::lc_tx_t fetch_en_o,
input lc_ctrl_pkg::lc_tx_t lc_hw_debug_en_i,
input lc_ctrl_pkg::lc_tx_t lc_dft_en_i,
input lc_ctrl_pkg::lc_tx_t lc_hw_debug_en_i,
input lc_ctrl_pkg::lc_tx_t lc_dft_en_i,

output pwr_boot_status_t boot_status_o,
// peripherals wakeup and reset requests
input [NumWkups-1:0] wakeups_i,
input [NumRstReqs-1:0] rstreqs_i,
input [NumWkups-1:0] wakeups_i,
input [NumRstReqs-1:0] rstreqs_i,

// cpu related inputs
input ndmreset_req_i,
Expand All @@ -88,6 +90,11 @@ module pwrmgr
output intr_wakeup_o

);

logic internal_reset_req;
logic strap_sampled;
logic ext_reset_req;

////////////////////////////////////////////////////
// Input handling //
////////////////////////////////////////////////////
Expand Down Expand Up @@ -504,6 +511,21 @@ module pwrmgr
{NumIntRstReqs{1'b1}},
slow_reset_en};

// TODO(#22711): Make this work also when `rstreqs` is structured differently.
assign internal_reset_req =|(
slow_peri_reqs.rstreqs &
{{NumSwRstReq{1'b1}}, // SW driven reset
{NumDebugRstReqs{1'b1}}, // debugger reset
{NumIntRstReqs{1'b1}}, // {ESC reset, slow_fsm}
// exclude the external async reset
{1'b0, slow_reset_en[0]}
}
);

// The MSB of `slow_peri_reqs.rstreqs` is the external reset request. We want it to always
// propagate, in order to continue from the Reset Wait state in the fast FSM.
assign ext_reset_req = slow_peri_reqs.rstreqs[NumRstReqs-1];

for (genvar i = 0; i < NumWkups; i++) begin : gen_wakeup_status
assign hw2reg.wake_status[i].de = 1'b1;
assign hw2reg.wake_status[i].d = peri_reqs_masked.wakeups[i];
Expand Down Expand Up @@ -574,7 +596,9 @@ module pwrmgr

assign low_power_hint = reg2hw.control.low_power_hint.q == LowPower;

pwrmgr_fsm u_fsm (
pwrmgr_fsm #(
.PwrFsmWaitForExtRst(PwrFsmWaitForExtRst)
) u_fsm (
.clk_i,
.rst_ni,
.clk_slow_i,
Expand Down Expand Up @@ -602,6 +626,8 @@ module pwrmgr
.fall_through_o (low_power_fall_through),
.abort_o (low_power_abort),
.clr_hint_o (clr_hint),
.int_reset_req_i (internal_reset_req),
.ext_reset_req_i (ext_reset_req),

// rstmgr
.pwr_rst_o (pwr_rst_o),
Expand Down Expand Up @@ -635,6 +661,7 @@ module pwrmgr

// pinmux and other peripherals
.strap_o,
.strap_sampled_o (strap_sampled), // to debug monitoring logic
.low_power_o
);

Expand Down Expand Up @@ -685,6 +712,16 @@ module pwrmgr
.intr_o (intr_wakeup_o)
);

////////////////////////////////////////////////////
// Routing sstaus signal outputs for monitoring
////////////////////////////////////////////////////
assign boot_status_o.cpu_fetch_en = fetch_en_o;
assign boot_status_o.rom_ctrl_status = rom_ctrl_i;
assign boot_status_o.lc_done = pwr_lc_i.lc_done;
assign boot_status_o.otp_done = otp_rsp.otp_done;
assign boot_status_o.clk_status = pwr_clk_i;
assign boot_status_o.light_reset_req = internal_reset_req;
assign boot_status_o.strap_sampled = strap_sampled;

////////////////////////////
/// Assertions
Expand Down
54 changes: 47 additions & 7 deletions hw/ip/pwrmgr/rtl/pwrmgr_fsm.sv
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@

`include "prim_assert.sv"

module pwrmgr_fsm import pwrmgr_pkg::*; import pwrmgr_reg_pkg::*;(
module pwrmgr_fsm
import pwrmgr_pkg::*;
import pwrmgr_reg_pkg::*;
#(
parameter bit PwrFsmWaitForExtRst = 0
) (
input clk_i,
input rst_ni,
input clk_slow_i,
Expand All @@ -33,6 +38,9 @@ module pwrmgr_fsm import pwrmgr_pkg::*; import pwrmgr_reg_pkg::*;(
output logic abort_o,
output logic clr_hint_o,
output logic clr_cfg_lock_o,
input logic int_reset_req_i, // internally generated reset request.
// Send to platform to assert reset
input logic ext_reset_req_i, // Internal Req held until ext reset deasserts

// rstmgr
output pwr_rst_req_t pwr_rst_o,
Expand Down Expand Up @@ -63,6 +71,7 @@ module pwrmgr_fsm import pwrmgr_pkg::*; import pwrmgr_reg_pkg::*;(

// pinmux
output logic strap_o,
output logic strap_sampled_o,
output logic low_power_o,

// processing elements
Expand Down Expand Up @@ -103,7 +112,6 @@ module pwrmgr_fsm import pwrmgr_pkg::*; import pwrmgr_reg_pkg::*;(

// strap sample should only happen on cold boot or when the
// the system goes through a reset cycle
logic strap_sampled;

// disable processing element fetching
lc_ctrl_pkg::lc_tx_t fetch_en_q, fetch_en_d;
Expand All @@ -118,6 +126,8 @@ module pwrmgr_fsm import pwrmgr_pkg::*; import pwrmgr_reg_pkg::*;(
logic otp_init;
logic lc_init;
logic low_power_q, low_power_d;
logic ext_rst_req_d, ext_rst_req_q;
logic ext_rst_pending_q;

assign pd_n_rsts_asserted = pwr_rst_i.rst_lc_src_n[PowerDomains-1:OffDomainSelStart] == '0 &
pwr_rst_i.rst_sys_src_n[PowerDomains-1:OffDomainSelStart] == '0;
Expand Down Expand Up @@ -153,6 +163,34 @@ module pwrmgr_fsm import pwrmgr_pkg::*; import pwrmgr_reg_pkg::*;(
assign reset_valid = reset_cause_q == LowPwrEntry ? main_pd_ni | pd_n_rsts_asserted :
reset_cause_q == HwReq ? all_rsts_asserted : 1'b0;

// Provide the ability to control the reset to OpenTitan RoT from an external source. The logic
// below makes sure that when an internal reset request is generated, it is held high until the
// external SoC reset logic asserts and then deasserts deasserts the external reset signal. The
// pwrmgr fast FSM is held in FastPwrStateResetWait state until the external reset deasserts.
// This ensure that the OT reset exit is synchronized with the rest of the SoC & platform.
if (PwrFsmWaitForExtRst) begin : gen_wait2ext_rst

assign ext_rst_req_d = ext_reset_req_i;

always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ext_rst_pending_q <= 1'b0;
ext_rst_req_q <= 1'b0;
end else begin
ext_rst_req_q <= ext_rst_req_d;
if (ext_rst_pending_q && !ext_rst_req_d && ext_rst_req_q) begin
ext_rst_pending_q <= 1'b0;
end else if (int_reset_req_i) begin
ext_rst_pending_q <= 1'b1;
end
end
end
end else begin : gen_no_wait2ext_rst
assign ext_rst_pending_q = 1'b0;
assign ext_rst_req_q = 1'b0;
assign ext_rst_req_d = 1'b0;
end : gen_no_wait2ext_rst

always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ack_pwrup_q <= 1'b0;
Expand Down Expand Up @@ -180,11 +218,11 @@ module pwrmgr_fsm import pwrmgr_pkg::*; import pwrmgr_reg_pkg::*;(

always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
strap_sampled <= 1'b0;
strap_sampled_o <= 1'b0;
end else if (&rst_sys_req_q) begin
strap_sampled <= 1'b0;
strap_sampled_o <= 1'b0;
end else if (strap_o) begin
strap_sampled <= 1'b1;
strap_sampled_o <= 1'b1;
end
end

Expand Down Expand Up @@ -338,7 +376,7 @@ module pwrmgr_fsm import pwrmgr_pkg::*; import pwrmgr_reg_pkg::*;(
end

FastPwrStateStrap: begin
strap_o = ~strap_sampled;
strap_o = ~strap_sampled_o;
state_d = FastPwrStateRomCheckDone;
end

Expand Down Expand Up @@ -471,7 +509,9 @@ module pwrmgr_fsm import pwrmgr_pkg::*; import pwrmgr_reg_pkg::*;(
// cleared before proceeding. This also implies if the system is under a persistent
// glitch, or if someone just turned off the power before pwrmgr turns it off itself,
// we will stay stuck here and perpetually hold the system in reset.
if (reset_valid && !reset_reqs_i[ResetMainPwrIdx]) begin
// Need to hold in reset until external reset deasserts (i.e. ext_rst_pending_q goes low)
if (reset_valid && !reset_reqs_i[ResetMainPwrIdx]
&& !ext_rst_pending_q ) begin
state_d = FastPwrStateLowPower;
end
end
Expand Down
10 changes: 10 additions & 0 deletions hw/ip/pwrmgr/rtl/pwrmgr_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,16 @@ package pwrmgr_pkg;
logic ndmreset_req;
} pwrmgr_cpu_t;

typedef struct packed {
lc_ctrl_pkg::lc_tx_t cpu_fetch_en;
rom_ctrl_pkg::pwrmgr_data_t [pwrmgr_reg_pkg::NumRomInputs-1:0] rom_ctrl_status;
logic lc_done;
logic otp_done;
logic strap_sampled;
logic light_reset_req;
pwr_clk_rsp_t clk_status;
} pwr_boot_status_t;

// exported resets

// default value for pwrmgr_ast_rsp_t (for dangling ports)
Expand Down
Loading

0 comments on commit d4aa482

Please sign in to comment.