[otp_ctrl] Update interface signals and LFSR reseeding
Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/otp_ctrl/otp_ctrl.core b/hw/ip/otp_ctrl/otp_ctrl.core
index ab26115..4c11419 100644
--- a/hw/ip/otp_ctrl/otp_ctrl.core
+++ b/hw/ip/otp_ctrl/otp_ctrl.core
@@ -8,12 +8,13 @@
filesets:
files_rtl:
depend:
+ - lowrisc:ip:otp_ctrl_pkg
- lowrisc:ip:tlul
- lowrisc:prim:all
- lowrisc:prim:ram_1p
- lowrisc:prim:otp
- lowrisc:prim:lfsr
- - lowrisc:ip:otp_ctrl_pkg
+ - lowrisc:ip:pwrmgr_pkg
files:
- rtl/otp_ctrl_reg_top.sv
- rtl/otp_ctrl_parity_reg.sv
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
index 32e21c4..0069696 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
@@ -18,8 +18,8 @@
// Enable asynchronous transitions on alerts.
parameter logic [NumAlerts-1:0] AlertAsyncOn = {NumAlerts{1'b1}},
// TODO: These constants have to be replaced by the silicon creator before taping out.
- parameter logic [TimerWidth-1:0] LfsrSeed = TimerWidth'(1'b1),
- parameter logic [TimerWidth-1:0][31:0] LfsrPerm = {
+ parameter logic [TimerWidth-1:0] TimerLfsrSeed = TimerWidth'(1'b1),
+ parameter logic [TimerWidth-1:0][31:0] TimerLfsrPerm = {
32'd13, 32'd17, 32'd29, 32'd11, 32'd28, 32'd12, 32'd33, 32'd27,
32'd05, 32'd39, 32'd31, 32'd21, 32'd15, 32'd01, 32'd24, 32'd37,
32'd32, 32'd38, 32'd26, 32'd34, 32'd08, 32'd10, 32'd04, 32'd02,
@@ -39,15 +39,12 @@
// Alerts
input prim_alert_pkg::alert_rx_t [NumAlerts-1:0] alert_rx_i,
output prim_alert_pkg::alert_tx_t [NumAlerts-1:0] alert_tx_o,
- // TODO: EDN interface for entropy updates
- input edn_otp_up_t edn_otp_up_i,
- // TODO: EDN interface for requesting entropy
+ // TODO: EDN interface
output otp_edn_req_t otp_edn_req_o,
input otp_edn_rsp_t otp_edn_rsp_i,
// Power manager interface
- input pwr_otp_init_req_t pwr_otp_init_req_i,
- output pwr_otp_init_rsp_t pwr_otp_init_rsp_o,
- output otp_pwr_state_t otp_pwr_state_o,
+ input pwrmgr_pkg::pwr_otp_req_t pwr_otp_req_i,
+ output pwrmgr_pkg::pwr_otp_rsp_t pwr_otp_rsp_o,
// Lifecycle transition command interface
input lc_otp_program_req_t lc_otp_program_req_i,
output lc_otp_program_rsp_t lc_otp_program_rsp_o,
@@ -169,7 +166,7 @@
// are pending. Hence, we signal the LCI/DAI idle state to the
// power manager
logic lci_idle;
- assign otp_pwr_state_o.idle = lci_idle & dai_idle;
+ assign pwr_otp_rsp_o.otp_idle = lci_idle & dai_idle;
//////////////////////////////////////
// Ctrl/Status CSRs, Errors, Alerts //
@@ -283,6 +280,7 @@
logic integ_chk_trig, cnsty_chk_trig;
logic [NumPart-1:0] integ_chk_req, integ_chk_ack;
logic [NumPart-1:0] cnsty_chk_req, cnsty_chk_ack;
+ logic lfsr_edn_req, lfsr_edn_ack;
assign integ_chk_trig = reg2hw.check_trigger.integrity.q &
reg2hw.check_trigger.integrity.qe;
@@ -290,30 +288,58 @@
reg2hw.check_trigger.consistency.qe;
otp_ctrl_lfsr_timer #(
- .LfsrSeed(LfsrSeed),
- .LfsrPerm(LfsrPerm),
+ .LfsrSeed(TimerLfsrSeed),
+ .LfsrPerm(TimerLfsrPerm),
.EntropyWidth(4)
) u_otp_ctrl_lfsr_timer (
.clk_i,
.rst_ni,
- .entropy_en_i ( edn_otp_up_i.en ),
+ .edn_req_o ( lfsr_edn_req ),
+ .edn_ack_i ( lfsr_edn_ack ),
// Lower entropy bits are used for reseeding secure erase LFSRs
- .entropy_i ( edn_otp_up_i.data[31:28] ),
+ .edn_data_i ( otp_edn_rsp_i.data[31:28] ),
// We can enable the timer once OTP has initialized.
- .timer_en_i ( pwr_otp_init_rsp_o.done ),
- .integ_chk_trig_i ( integ_chk_trig ),
- .cnsty_chk_trig_i ( cnsty_chk_trig ),
- .chk_pending_o ( chk_pending ),
- .timeout_i ( reg2hw.check_timeout.q ),
+ // Note that this is only the initial release that gets
+ // the timer FSM into an operational state.
+ // Whether or not the timers / background checks are
+ // activated depends on the CSR configuration (by default
+ // they are switched off).
+ .timer_en_i ( pwr_otp_rsp_o.otp_done ),
+ .integ_chk_trig_i ( integ_chk_trig ),
+ .cnsty_chk_trig_i ( cnsty_chk_trig ),
+ .chk_pending_o ( chk_pending ),
+ .timeout_i ( reg2hw.check_timeout.q ),
.integ_period_msk_i ( reg2hw.integrity_check_period.q ),
.cnsty_period_msk_i ( reg2hw.consistency_check_period.q ),
- .integ_chk_req_o ( integ_chk_req ),
- .cnsty_chk_req_o ( cnsty_chk_req ),
- .integ_chk_ack_i ( integ_chk_ack ),
- .cnsty_chk_ack_i ( cnsty_chk_ack ),
- .escalate_en_i ( lc_escalate_en_i ),
- .chk_timeout_o ( chk_timeout ),
- .fsm_err_o ( lfsr_fsm_err )
+ .integ_chk_req_o ( integ_chk_req ),
+ .cnsty_chk_req_o ( cnsty_chk_req ),
+ .integ_chk_ack_i ( integ_chk_ack ),
+ .cnsty_chk_ack_i ( cnsty_chk_ack ),
+ .escalate_en_i ( lc_escalate_en_i ),
+ .chk_timeout_o ( chk_timeout ),
+ .fsm_err_o ( lfsr_fsm_err )
+ );
+
+ /////////////////////
+ // EDN Arbitration //
+ /////////////////////
+
+ // Both the key derivation and LFSR reseeding are low bandwidth,
+ // hence they can share the same EDN interface.
+ logic key_edn_req, key_edn_ack;
+ prim_arbiter_tree #(
+ .N(2),
+ .EnDataPort(0)
+ ) u_edn_arb (
+ .clk_i,
+ .rst_ni,
+ .req_i ( {lfsr_edn_req, key_edn_req} ),
+ .data_i ( '{default: '0} ),
+ .gnt_o ( {lfsr_edn_ack, key_edn_ack} ),
+ .idx_o ( ), // unused
+ .valid_o ( otp_edn_req_o.req ),
+ .data_o ( ), // unused
+ .ready_i ( otp_edn_rsp_i.ack )
);
///////////////////////////////
@@ -502,8 +528,8 @@
otp_ctrl_dai u_otp_ctrl_dai (
.clk_i,
.rst_ni,
- .init_req_i ( pwr_otp_init_req_i.init ),
- .init_done_o ( pwr_otp_init_rsp_o.done ),
+ .init_req_i ( pwr_otp_req_i.otp_init ),
+ .init_done_o ( pwr_otp_rsp_o.otp_done ),
.part_init_req_o ( part_init_req ),
.part_init_done_i ( part_init_done ),
.escalate_en_i ( lc_escalate_en_i ),
@@ -586,15 +612,16 @@
otp_ctrl_kdi i_otp_ctrl_kdi (
.clk_i,
.rst_ni,
- .key_deriv_en_i ( pwr_otp_init_rsp_o.done ),
+ .key_deriv_en_i ( pwr_otp_rsp_o.otp_done ),
.escalate_en_i ( lc_escalate_en_i ),
.fsm_err_o ( key_deriv_fsm_err ),
.scrmbl_key_seed_valid_i ( scrmbl_key_seed_valid ),
.flash_data_key_seed_i ( flash_data_key_seed ),
.flash_addr_key_seed_i ( flash_addr_key_seed ),
.sram_data_key_seed_i ( sram_data_key_seed ),
- .otp_edn_req_o,
- .otp_edn_rsp_i,
+ .edn_req_o ( key_edn_req ),
+ .edn_ack_i ( key_edn_ack ),
+ .edn_data_i ( otp_edn_rsp_i.data ),
.lc_otp_token_req_i ,
.lc_otp_token_rsp_o ,
.flash_otp_key_req_i,
@@ -725,10 +752,6 @@
end
end
- // TODO: remove this once connected.
- logic unused_entropy;
- assign unused_entropy = ^edn_otp_up_i.data;
-
//////////////////////////////////
// Buffered Data Output Mapping //
//////////////////////////////////
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv
index 5ce5b0a..0a3e1e0 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv
@@ -30,8 +30,9 @@
input logic [FlashKeySeedWidth-1:0] flash_addr_key_seed_i,
input logic [SramKeySeedWidth-1:0] sram_data_key_seed_i,
// EDN interface for requesting entropy
- output otp_edn_req_t otp_edn_req_o,
- input otp_edn_rsp_t otp_edn_rsp_i,
+ output logic edn_req_o,
+ input edn_ack_i,
+ input [31:0] edn_data_i,
// Lifecycle hashing request
input lc_otp_token_rsp_t lc_otp_token_req_i,
output lc_otp_token_rsp_t lc_otp_token_rsp_o,
@@ -57,7 +58,7 @@
// tie-off and unused assignments for preventing lint messages
assign fsm_err_o = 1'b0;
- assign otp_edn_req_o = '0;
+ assign edn_req_o = '0;
assign lc_otp_token_rsp_o = '0;
assign flash_otp_key_rsp_o = '0;
assign sram_otp_key_rsp_o = '0;
@@ -75,7 +76,8 @@
flash_data_key_seed_i,
flash_addr_key_seed_i,
sram_data_key_seed_i,
- otp_edn_rsp_i,
+ edn_ack_i,
+ edn_data_i,
lc_otp_token_req_i,
flash_otp_key_req_i,
sram_otp_key_req_i,
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv
index 69f8066..05a4b48 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv
@@ -19,7 +19,8 @@
// programmed. If a particular check times out, chk_timeout_o will be asserted, which will raise
// an alert via the error logic.
//
-// If needed, the LFSR can be reseeded with fresh entropy from the CSRNG via entropy_i.
+// The EntropyWidth LSBs of the LFSR are periodically reseeded with fresh entropy from
+// CSRNG every 2^ReseedTimerWidth cycles.
//
// It is also possible to trigger one-off checks via integ_chk_trig_i and cnsty_chk_trig_i.
// This can be useful if SW chooses to leave the periodic checks disabled.
@@ -28,20 +29,24 @@
`include "prim_assert.sv"
module otp_ctrl_lfsr_timer import otp_ctrl_pkg::*; #(
- parameter logic [TimerWidth-1:0] LfsrSeed = TimerWidth'(1'b1),
- parameter logic [TimerWidth-1:0][31:0] LfsrPerm = {
+ // Entropy reseeding is triggered every time this counter expires.
+ parameter int ReseedTimerWidth = 16,
+ // Number of LFSR LSBs to reseed
+ parameter int EntropyWidth = 4,
+ parameter logic [TimerWidth-1:0] LfsrSeed = TimerWidth'(1'b1),
+ parameter logic [TimerWidth-1:0][31:0] LfsrPerm = {
32'd13, 32'd17, 32'd29, 32'd11, 32'd28, 32'd12, 32'd33, 32'd27,
32'd05, 32'd39, 32'd31, 32'd21, 32'd15, 32'd01, 32'd24, 32'd37,
32'd32, 32'd38, 32'd26, 32'd34, 32'd08, 32'd10, 32'd04, 32'd02,
32'd19, 32'd00, 32'd20, 32'd06, 32'd25, 32'd22, 32'd03, 32'd35,
32'd16, 32'd14, 32'd23, 32'd07, 32'd30, 32'd09, 32'd18, 32'd36
- },
- parameter int EntropyWidth = 8
+ }
) (
input clk_i,
input rst_ni,
- input entropy_en_i, // entropy update pulse from CSRNG
- input [EntropyWidth-1:0] entropy_i, // from CSRNG
+ output logic edn_req_o, // request to EDN
+ input edn_ack_i, // ack from EDN
+ input [EntropyWidth-1:0] edn_data_i, // from EDN
input timer_en_i, // enable timer
input integ_chk_trig_i, // one-off trigger for integrity check
input cnsty_chk_trig_i, // one-off trigger for consistency check
@@ -58,6 +63,18 @@
output logic fsm_err_o // the FSM has reached an invalid state
);
+ ////////////////////
+ // Reseed counter //
+ ////////////////////
+
+ logic reseed_en;
+ logic [ReseedTimerWidth-1:0] reseed_timer_d, reseed_timer_q;
+
+ assign reseed_timer_d = (reseed_timer_q > '0) ? reseed_timer_q - 1'b1 :
+ (reseed_en) ? {ReseedTimerWidth{1'b1}} : '0;
+ assign edn_req_o = (reseed_timer_q == '0);
+ assign reseed_en = edn_req_o & edn_ack_i;
+
//////////
// PRNG //
//////////
@@ -78,8 +95,8 @@
.rst_ni,
.seed_en_i ( 1'b0 ),
.seed_i ( '0 ),
- .lfsr_en_i ( lfsr_en | entropy_en_i ),
- .entropy_i ( entropy_i & {EntropyWidth{entropy_en_i}} ),
+ .lfsr_en_i ( lfsr_en | reseed_en ),
+ .entropy_i ( edn_data_i & {EntropyWidth{reseed_en}} ),
.state_o ( lfsr_state )
);
@@ -274,6 +291,7 @@
integ_chk_req_q <= '0;
cnsty_chk_req_q <= '0;
chk_timeout_q <= 1'b0;
+ reseed_timer_q <= '0;
end else begin
state_q <= state_d;
integ_cnt_q <= integ_cnt_d;
@@ -281,6 +299,7 @@
integ_chk_req_q <= integ_chk_req_d;
cnsty_chk_req_q <= cnsty_chk_req_d;
chk_timeout_q <= chk_timeout_d;
+ reseed_timer_q <= reseed_timer_d;
end
end
@@ -288,6 +307,7 @@
// Assertions //
////////////////
+ `ASSERT_KNOWN(EntropyReqKnown_A, entropy_req_o)
`ASSERT_KNOWN(ChkPendingKnown_A, chk_pending_o)
`ASSERT_KNOWN(IntegChkReqKnown_A, integ_chk_req_o)
`ASSERT_KNOWN(CnstyChkReqKnown_A, cnsty_chk_req_o)