[lc_ctrl] Add life cycle state diversification output

Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl.sv
index c45af38..a9e7f5e 100644
--- a/hw/ip/lc_ctrl/rtl/lc_ctrl.sv
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl.sv
@@ -14,7 +14,13 @@
   // Enable asynchronous transitions on alerts.
   parameter logic [NumAlerts-1:0] AlertAsyncOn = {NumAlerts{1'b1}},
   // Idcode value for the JTAG.
-  parameter logic [31:0]          IdcodeValue  = 32'h00000001
+  parameter logic [31:0]          IdcodeValue  = 32'h00000001,
+  // Random netlist constants
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivInv  = LcKeymgrDivWidth'(0),
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivTest = LcKeymgrDivWidth'(1),
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivProd = LcKeymgrDivWidth'(2),
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivDev  = LcKeymgrDivWidth'(3),
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivRma  = LcKeymgrDivWidth'(4)
 ) (
   input                                              clk_i,
   input                                              rst_ni,
@@ -67,7 +73,9 @@
   // The ack is synced to the lc clock domain using prim_lc_sync.
   output lc_flash_rma_seed_t                         lc_flash_rma_seed_o,
   output lc_tx_t                                     lc_flash_rma_req_o,
-  input  lc_tx_t                                     lc_flash_rma_ack_i
+  input  lc_tx_t                                     lc_flash_rma_ack_i,
+  // State group diversification value for keymgr
+  output lc_keymgr_div_t                             lc_keymgr_div_o
 );
 
   ////////////////////////
@@ -446,7 +454,13 @@
   assign lc_otp_token_o.token_input = transition_token_q;
   assign lc_flash_rma_seed_o = transition_token_q[RmaSeedWidth-1:0];
 
-  lc_ctrl_fsm u_lc_ctrl_fsm (
+  lc_ctrl_fsm #(
+    .RndCnstLcKeymgrDivInv  ( RndCnstLcKeymgrDivInv  ),
+    .RndCnstLcKeymgrDivTest ( RndCnstLcKeymgrDivTest ),
+    .RndCnstLcKeymgrDivProd ( RndCnstLcKeymgrDivProd ),
+    .RndCnstLcKeymgrDivDev  ( RndCnstLcKeymgrDivDev  ),
+    .RndCnstLcKeymgrDivRma  ( RndCnstLcKeymgrDivRma  )
+  ) u_lc_ctrl_fsm (
     .clk_i,
     .rst_ni,
     .init_req_i             ( lc_init                         ),
@@ -492,7 +506,8 @@
     .lc_clk_byp_req_o,
     .lc_clk_byp_ack_i      ( lc_clk_byp_ack                  ),
     .lc_flash_rma_req_o,
-    .lc_flash_rma_ack_i    ( lc_flash_rma_ack                )
+    .lc_flash_rma_ack_i    ( lc_flash_rma_ack                ),
+    .lc_keymgr_div_o
   );
 
   ////////////////
@@ -515,5 +530,6 @@
   `ASSERT_KNOWN(LcClkBypReqKnown_A,     lc_clk_byp_req_o     )
   `ASSERT_KNOWN(LcFlashRmaSeedKnown_A,  lc_flash_rma_seed_o  )
   `ASSERT_KNOWN(LcFlashRmaReqKnown_A,   lc_flash_rma_req_o   )
+  `ASSERT_KNOWN(LcKeymgrDiv_A,          lc_keymgr_div_o      )
 
 endmodule : lc_ctrl
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_fsm.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_fsm.sv
index 9da0b3c..b66c9a8 100644
--- a/hw/ip/lc_ctrl/rtl/lc_ctrl_fsm.sv
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_fsm.sv
@@ -6,7 +6,13 @@
 
 module lc_ctrl_fsm
   import lc_ctrl_pkg::*;
-(
+#(// Random netlist constants
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivInv  = LcKeymgrDivWidth'(0),
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivTest = LcKeymgrDivWidth'(1),
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivProd = LcKeymgrDivWidth'(2),
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivDev  = LcKeymgrDivWidth'(3),
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivRma  = LcKeymgrDivWidth'(4)
+) (
   // This module is combinational, but we
   // need the clock and reset for the assertions.
   input                         clk_i,
@@ -66,7 +72,9 @@
   input  lc_tx_t                lc_clk_byp_ack_i,
   // Request and feedback to/from flash controller
   output lc_tx_t                lc_flash_rma_req_o,
-  input  lc_tx_t                lc_flash_rma_ack_i
+  input  lc_tx_t                lc_flash_rma_ack_i,
+  // State group diversification value for keymgr
+  output lc_keymgr_div_t        lc_keymgr_div_o
 );
 
   ///////////////
@@ -413,7 +421,13 @@
   );
 
   // LC signal decoder and broadcasting logic.
-  lc_ctrl_signal_decode u_lc_ctrl_signal_decode (
+  lc_ctrl_signal_decode #(
+    .RndCnstLcKeymgrDivInv  ( RndCnstLcKeymgrDivInv  ),
+    .RndCnstLcKeymgrDivTest ( RndCnstLcKeymgrDivTest ),
+    .RndCnstLcKeymgrDivProd ( RndCnstLcKeymgrDivProd ),
+    .RndCnstLcKeymgrDivDev  ( RndCnstLcKeymgrDivDev  ),
+    .RndCnstLcKeymgrDivRma  ( RndCnstLcKeymgrDivRma  )
+  ) u_lc_ctrl_signal_decode (
     .clk_i,
     .rst_ni,
     .lc_state_valid_i   ( lc_state_valid_q ),
@@ -428,7 +442,8 @@
     .lc_provision_wr_en_o,
     .lc_provision_rd_en_o,
     .lc_keymgr_en_o,
-    .lc_escalate_en_o
+    .lc_escalate_en_o,
+    .lc_keymgr_div_o
   );
 
   // Conditional signals set by main FSM.
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
index 4821692..3f76149 100644
--- a/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
@@ -205,6 +205,9 @@
   parameter int RmaSeedWidth = 32;
   typedef logic [RmaSeedWidth-1:0] lc_flash_rma_seed_t;
 
+  parameter int LcKeymgrDivWidth = 64;
+  typedef logic [LcKeymgrDivWidth-1:0] lc_keymgr_div_t;
+
   ////////////////////
   // Main FSM State //
   ////////////////////
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_signal_decode.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_signal_decode.sv
index 75507d3..5e68738 100644
--- a/hw/ip/lc_ctrl/rtl/lc_ctrl_signal_decode.sv
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_signal_decode.sv
@@ -6,7 +6,19 @@
 
 module lc_ctrl_signal_decode
   import lc_ctrl_pkg::*;
-(
+#(
+  // Random netlist constants
+  // SCRAP, RAW, TEST_LOCKED*, INVALID
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivInv  = LcKeymgrDivWidth'(0),
+  // TEST_UNLOCKED*
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivTest = LcKeymgrDivWidth'(1),
+  // PROD, PROD_END
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivProd = LcKeymgrDivWidth'(2),
+  // DEV
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivDev  = LcKeymgrDivWidth'(3),
+  // RMA
+  parameter lc_keymgr_div_t RndCnstLcKeymgrDivRma  = LcKeymgrDivWidth'(4)
+) (
   input                  clk_i,
   input                  rst_ni,
   // Life cycle state vector.
@@ -24,7 +36,9 @@
   output lc_tx_t         lc_provision_wr_en_o,
   output lc_tx_t         lc_provision_rd_en_o,
   output lc_tx_t         lc_keymgr_en_o,
-  output lc_tx_t         lc_escalate_en_o
+  output lc_tx_t         lc_escalate_en_o,
+  // State group diversification value for keymgr
+  output lc_keymgr_div_t lc_keymgr_div_o
 );
 
   //////////////////////////
@@ -39,6 +53,7 @@
   lc_tx_t lc_provision_rd_en_d, lc_provision_rd_en_q;
   lc_tx_t lc_keymgr_en_d, lc_keymgr_en_q;
   lc_tx_t lc_escalate_en_d, lc_escalate_en_q;
+  lc_keymgr_div_t lc_keymgr_div_d, lc_keymgr_div_q;
 
   always_comb begin : p_lc_signal_decode
     // Life cycle control signal defaults
@@ -50,7 +65,8 @@
     lc_provision_rd_en_d = Off;
     lc_keymgr_en_d       = Off;
     lc_escalate_en_d     = Off;
-
+    // Set to invalid diversification value by default.
+    lc_keymgr_div_d      = RndCnstLcKeymgrDivInv;
     // The escalation life cycle signal is always decoded, no matter
     // which state we currently are in.
     if (esc_wipe_secrets_i) begin
@@ -66,8 +82,7 @@
                                                 FlashRmaSt,
                                                 TokenHashSt,
                                                 TokenCheck0St,
-                                                TokenCheck1St,
-                                                TransProgSt}) begin
+                                                TokenCheck1St}) begin
       unique case (lc_state_i)
         ///////////////////////////////////////////////////////////////////
         // Enable DFT and debug functionality, including the CPU in the
@@ -80,6 +95,7 @@
           lc_nvm_debug_en_d = On;
           lc_hw_debug_en_d  = On;
           lc_cpu_en_d       = On;
+          lc_keymgr_div_d   = RndCnstLcKeymgrDivTest;
         end
         ///////////////////////////////////////////////////////////////////
         // Enable production functions
@@ -87,6 +103,7 @@
           lc_cpu_en_d          = On;
           lc_keymgr_en_d       = On;
           lc_provision_rd_en_d = On;
+          lc_keymgr_div_d      = RndCnstLcKeymgrDivProd;
           // Only allow provisioning if the defice has not yet been personalized.
           if (lc_id_state_i == LcIdBlank) begin
             lc_provision_wr_en_d = On;
@@ -99,6 +116,7 @@
           lc_cpu_en_d          = On;
           lc_keymgr_en_d       = On;
           lc_provision_rd_en_d = On;
+          lc_keymgr_div_d      = RndCnstLcKeymgrDivDev;
           // Only allow provisioning if the defice has not yet been personalized.
           if (lc_id_state_i == LcIdBlank) begin
             lc_provision_wr_en_d = On;
@@ -113,6 +131,7 @@
           lc_cpu_en_d          = On;
           lc_keymgr_en_d       = On;
           lc_provision_rd_en_d = On;
+          lc_keymgr_div_d      = RndCnstLcKeymgrDivRma;
           // Only allow provisioning if the defice has not yet been personalized.
           if (lc_id_state_i == LcIdBlank) begin
             lc_provision_wr_en_d = On;
@@ -138,6 +157,7 @@
   assign lc_provision_rd_en_o = lc_provision_rd_en_q;
   assign lc_keymgr_en_o       = lc_keymgr_en_q;
   assign lc_escalate_en_o     = lc_escalate_en_q;
+  assign lc_keymgr_div_o      = lc_keymgr_div_q;
 
   always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
     if (!rst_ni) begin
@@ -149,6 +169,7 @@
       lc_provision_rd_en_q <= Off;
       lc_keymgr_en_q       <= Off;
       lc_escalate_en_q     <= Off;
+      lc_keymgr_div_q      <= RndCnstLcKeymgrDivInv;
     end else begin
       lc_dft_en_q          <= lc_dft_en_d;
       lc_nvm_debug_en_q    <= lc_nvm_debug_en_d;
@@ -158,6 +179,7 @@
       lc_provision_rd_en_q <= lc_provision_rd_en_d;
       lc_keymgr_en_q       <= lc_keymgr_en_d;
       lc_escalate_en_q     <= lc_escalate_en_d;
+      lc_keymgr_div_q      <= lc_keymgr_div_d;
     end
   end
 
@@ -165,6 +187,19 @@
   // Assertions //
   ////////////////
 
+  // Need to make sure that the random netlist constants
+  // are unique.
+  `ASSERT_INIT(LcKeymgrDivUnique0_A, !(RndCnstLcKeymgrDivInvalid inside {RndCnstLcKeymgrDivTest,
+                                                                         RndCnstLcKeymgrDivProd,
+                                                                         RndCnstLcKeymgrDivDev,
+                                                                         RndCnstLcKeymgrDivRma}))
+  `ASSERT_INIT(LcKeymgrDivUnique1_A, !(RndCnstLcKeymgrDivTest    inside {RndCnstLcKeymgrDivProd,
+                                                                         RndCnstLcKeymgrDivDev,
+                                                                         RndCnstLcKeymgrDivRma}))
+  `ASSERT_INIT(LcKeymgrDivUnique2_A, !(RndCnstLcKeymgrDivProd    inside {RndCnstLcKeymgrDivDev,
+                                                                         RndCnstLcKeymgrDivRma}))
+  `ASSERT_INIT(LcKeymgrDivUnique3_A, !(RndCnstLcKeymgrDivDev     inside {RndCnstLcKeymgrDivRma}))
+
   `ASSERT(SignalsAreOffWhenNotEnabled_A,
       !lc_state_valid_i
       |=>
@@ -175,7 +210,8 @@
       lc_provision_wr_en_o == Off &&
       lc_provision_rd_en_o == Off &&
       lc_keymgr_en_o == Off &&
-      lc_dft_en_o == Off)
+      lc_dft_en_o == Off &&
+      lc_keymgr_div_o == RndCnstLcKeymgrDivInv)
 
   `ASSERT(EscalationAlwaysDecoded_A,
       (lc_escalate_en_o == On) == $past(esc_wipe_secrets_i))