[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)