[otp_ctrl] Add KDI stub, define errors for aux FSMs
Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/otp_ctrl/data/otp_ctrl.hjson b/hw/ip/otp_ctrl/data/otp_ctrl.hjson
index 93777d0..d3d8fbb 100644
--- a/hw/ip/otp_ctrl/data/otp_ctrl.hjson
+++ b/hw/ip/otp_ctrl/data/otp_ctrl.hjson
@@ -256,13 +256,37 @@
}
{ bits: "9"
name: "TIMEOUT_ERROR"
- desc: "Set to 1 if an integrity or consistency check times out. This raises an otp_check_failed alert and is an unrecoverable error condition."
+ desc: '''
+ Set to 1 if an integrity or consistency check times out.
+ This raises an otp_check_failed alert and is an unrecoverable error condition.
+ '''
}
{ bits: "10"
+ name: "LFSR_FSM_ERROR"
+ desc: '''
+ Set to 1 if the LFSR timer FSM has reached an invalid state.
+ This raises an otp_check_failed alert and is an unrecoverable error condition.
+ '''
+ }
+ { bits: "11"
+ name: "SCRAMBLING_FSM_ERROR"
+ desc: '''
+ Set to 1 if the scrambling datapath FSM has reached an invalid state.
+ This raises an otp_check_failed alert and is an unrecoverable error condition.
+ '''
+ }
+ { bits: "12"
+ name: "KEY_DERIV_FSM_ERROR"
+ desc: '''
+ Set to 1 if the key derivation FSM has reached an invalid state.
+ This raises an otp_check_failed alert and is an unrecoverable error condition.
+ '''
+ }
+ { bits: "13"
name: "DAI_IDLE"
desc: "Set to 1 if the DAI is idle and ready to accept commands."
}
- { bits: "11"
+ { bits: "14"
name: "CHECK_PENDING"
desc: "Set to 1 if an integrity or consistency check triggered by the LFSR timer or via !!CHECK_TRIGGER is pending."
}
@@ -530,7 +554,7 @@
Register write enable for !!CHECK_TRIGGER.
''',
swaccess: "rw1c",
- hwaccess: "hro",
+ hwaccess: "none",
fields: [
{ bits: "0",
desc: '''
@@ -571,7 +595,7 @@
Register write enable for !!INTEGRITY_CHECK_PERIOD and !!CONSISTENCY_CHECK_PERIOD.
''',
swaccess: "rw1c",
- hwaccess: "hro",
+ hwaccess: "none",
fields: [
{ bits: "0",
desc: '''
diff --git a/hw/ip/otp_ctrl/otp_ctrl.core b/hw/ip/otp_ctrl/otp_ctrl.core
index 716ac7e..ab26115 100644
--- a/hw/ip/otp_ctrl/otp_ctrl.core
+++ b/hw/ip/otp_ctrl/otp_ctrl.core
@@ -18,11 +18,12 @@
- rtl/otp_ctrl_reg_top.sv
- rtl/otp_ctrl_parity_reg.sv
- rtl/otp_ctrl_scrmbl.sv
- - rtl/otp_ctrl_dai.sv
- - rtl/otp_ctrl_lci.sv
+ - rtl/otp_ctrl_lfsr_timer.sv
- rtl/otp_ctrl_part_unbuf.sv
- rtl/otp_ctrl_part_buf.sv
- - rtl/otp_ctrl_lfsr_timer.sv
+ - rtl/otp_ctrl_dai.sv
+ - rtl/otp_ctrl_kdi.sv
+ - rtl/otp_ctrl_lci.sv
- rtl/otp_ctrl.sv
file_type: systemVerilogSource
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
index 3a198b4..4d86609 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
@@ -11,7 +11,12 @@
import otp_ctrl_pkg::*;
import otp_ctrl_reg_pkg::*;
#(
- parameter logic [NumAlerts-1:0] AlertAsyncOn = {NumAlerts{1'b1}},
+ // TODO: set this when integrating the module into the top-level.
+ // There is no limit on the number of SRAM key request generation slots,
+ // since each requested key is ephemeral.
+ parameter int NumSramKeyReqSlots = 2,
+ // 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 = {
@@ -22,40 +27,49 @@
32'd16, 32'd14, 32'd23, 32'd07, 32'd30, 32'd09, 32'd18, 32'd36
}
) (
- input clk_i,
- input rst_ni,
+ input clk_i,
+ input rst_ni,
// TODO: signals to AST
// Bus Interface (device)
- input tlul_pkg::tl_h2d_t tl_i,
- output tlul_pkg::tl_d2h_t tl_o,
+ input tlul_pkg::tl_h2d_t tl_i,
+ output tlul_pkg::tl_d2h_t tl_o,
// Interrupt Requests
- output logic intr_otp_operation_done_o,
- output logic intr_otp_error_o,
+ output logic intr_otp_operation_done_o,
+ output logic intr_otp_error_o,
// 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: Complete entropy interface
- input otp_entropy_t entropy_i,
+ 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
+ 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 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,
// 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,
+ input lc_otp_program_req_t lc_otp_program_req_i,
+ output lc_otp_program_rsp_t lc_otp_program_rsp_o,
// Lifecycle hashing interface for raw unlock
- input lc_otp_token_req_t lc_otp_token_req_i,
- output lc_otp_token_rsp_t lc_otp_token_rsp_o,
+ input lc_otp_token_req_t lc_otp_token_req_i,
+ output lc_otp_token_rsp_t lc_otp_token_rsp_o,
// Lifecycle broadcast inputs
- input lc_tx_t lc_escalate_en_i,
- input lc_tx_t lc_provision_en_i,
- input lc_tx_t lc_test_en_i,
+ input lc_tx_t lc_escalate_en_i,
+ input lc_tx_t lc_provision_en_i,
+ input lc_tx_t lc_test_en_i,
// OTP broadcast outputs
- output otp_lc_data_t otp_lc_data_o,
- output keymgr_key_t otp_keymgr_key_o,
- output flash_key_t otp_flash_key_o,
+ output otp_lc_data_t otp_lc_data_o,
+ output otp_keymgr_key_t otp_keymgr_key_o,
+ // Scrambling key requests
+ input flash_otp_key_req_t flash_otp_key_req_i,
+ output flash_otp_key_rsp_t flash_otp_key_rsp_o,
+ input sram_otp_key_req_t [NumSramKeyReqSlots-1:0] sram_otp_key_req_i,
+ output sram_otp_key_rsp_t [NumSramKeyReqSlots-1:0] sram_otp_key_rsp_o,
+ input otbn_otp_key_req_t otbn_otp_key_req_i,
+ output otbn_otp_key_rsp_t otbn_otp_key_rsp_o,
// Hardware config bits
- output logic [NumHwCfgBits-1:0] hw_cfg_o
+ output logic [NumHwCfgBits-1:0] hw_cfg_o
);
import prim_util_pkg::vbits;
@@ -169,6 +183,7 @@
logic otp_operation_done, otp_error;
logic otp_fatal_error, otp_check_failed;
logic chk_pending, chk_timeout;
+ logic lfsr_fsm_err, key_deriv_fsm_err, scrmbl_fsm_err;
always_comb begin : p_errors_alerts
hw2reg.err_code = part_error;
otp_fatal_error = 1'b0;
@@ -190,13 +205,20 @@
otp_check_failed |= part_error[k] inside {ParityErr,
IntegErr,
CnstyErr,
- FsmErr} | chk_timeout;
+ FsmErr} |
+ chk_timeout |
+ lfsr_fsm_err |
+ scrmbl_fsm_err |
+ key_deriv_fsm_err;
end
end
// Assign these to the status register.
assign hw2reg.status = {chk_pending,
dai_idle,
+ key_deriv_fsm_err,
+ scrmbl_fsm_err,
+ lfsr_fsm_err,
chk_timeout,
part_errors_reduced};
// If we got an error, we trigger an interrupt.
@@ -276,9 +298,9 @@
) u_otp_ctrl_lfsr_timer (
.clk_i,
.rst_ni,
- .entropy_en_i ( entropy_i.en ),
+ .entropy_en_i ( edn_otp_up_i.en ),
// Lower entropy bits are used for reseeding secure erase LFSRs
- .entropy_i ( entropy_i.data[31:28] ),
+ .entropy_i ( edn_otp_up_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 ),
@@ -291,7 +313,9 @@
.cnsty_chk_req_o ( cnsty_chk_req ),
.integ_chk_ack_i ( integ_chk_ack ),
.cnsty_chk_ack_i ( cnsty_chk_ack ),
- .chk_timeout_o ( chk_timeout )
+ .escalate_en_i ( lc_escalate_en_i ),
+ .chk_timeout_o ( chk_timeout ),
+ .fsm_err_o ( lfsr_fsm_err )
);
///////////////////////////////
@@ -305,16 +329,16 @@
logic [OtpAddrWidth-1:0] addr; // Halfword address.
} otp_bundle_t;
- logic [NumPart+1:0] part_otp_arb_req, part_otp_arb_gnt;
- otp_bundle_t part_otp_arb_bundle [NumPart+2];
+ logic [NumAgents-1:0] part_otp_arb_req, part_otp_arb_gnt;
+ otp_bundle_t part_otp_arb_bundle [NumAgents];
logic otp_arb_valid, otp_arb_ready;
- logic [vbits(NumPart+2)-1:0] otp_arb_idx;
+ logic [vbits(NumAgents)-1:0] otp_arb_idx;
otp_bundle_t otp_arb_bundle;
// The OTP interface is arbitrated on a per-cycle basis, meaning that back-to-back
// transactions can be completely independent.
prim_arbiter_tree #(
- .N(NumPart+2),
+ .N(NumAgents),
.DW($bits(otp_bundle_t))
) u_otp_arb (
.clk_i,
@@ -363,13 +387,13 @@
);
logic otp_fifo_valid;
- logic [NumPartWidth-1:0] otp_part_idx;
- logic [NumPart+1:0] part_otp_rvalid;
+ logic [vbits(NumAgents)-1:0] otp_part_idx;
+ logic [NumAgents-1:0] part_otp_rvalid;
// We can have up to two OTP commands in flight, hence we size this to be 2 deep.
// The partitions can unconditionally sink requested data.
prim_fifo_sync #(
- .Width(NumPartWidth),
+ .Width(vbits(NumAgents)),
.Depth(2)
) u_otp_rsp_fifo (
.clk_i,
@@ -406,21 +430,21 @@
// eventually release their locks for this to be fair.
typedef struct packed {
otp_scrmbl_cmd_e cmd;
- logic [ConstSelWidth-1:0] sel;
+ logic [ConstSelWidth-1:0] sel;
logic [ScrmblBlockWidth-1:0] data;
logic valid;
} scrmbl_bundle_t;
- logic [NumPart:0] part_scrmbl_mtx_req, part_scrmbl_mtx_gnt;
- scrmbl_bundle_t part_scrmbl_req_bundle [NumPart+1];
+ logic [NumAgents-1:0] part_scrmbl_mtx_req, part_scrmbl_mtx_gnt;
+ scrmbl_bundle_t part_scrmbl_req_bundle [NumAgents];
scrmbl_bundle_t scrmbl_req_bundle;
- logic [vbits(NumPart+1)-1:0] scrmbl_mtx_idx;
+ logic [vbits(NumAgents)-1:0] scrmbl_mtx_idx;
logic scrmbl_mtx_valid;
// Note that arbiter decisions do not change when backpressured.
// Hence, the idx_o signal is guaranteed to remain stable until ack'ed.
prim_arbiter_tree #(
- .N(NumPart+1),
+ .N(NumAgents),
.DW($bits(scrmbl_bundle_t))
) u_scrmbl_mtx (
.clk_i,
@@ -445,18 +469,20 @@
logic [ScrmblBlockWidth-1:0] part_scrmbl_rsp_data;
logic scrmbl_arb_req_ready, scrmbl_arb_rsp_valid;
- logic [NumPart:0] part_scrmbl_req_ready, part_scrmbl_rsp_valid;
+ logic [NumAgents-1:0] part_scrmbl_req_ready, part_scrmbl_rsp_valid;
otp_ctrl_scrmbl u_scrmbl (
.clk_i,
.rst_ni,
- .cmd_i ( scrmbl_req_bundle.cmd ),
- .sel_i ( scrmbl_req_bundle.sel ),
- .data_i ( scrmbl_req_bundle.data ),
- .valid_i ( scrmbl_req_bundle.valid ),
- .ready_o ( scrmbl_arb_req_ready ),
- .data_o ( part_scrmbl_rsp_data ),
- .valid_o ( scrmbl_arb_rsp_valid )
+ .cmd_i ( scrmbl_req_bundle.cmd ),
+ .sel_i ( scrmbl_req_bundle.sel ),
+ .data_i ( scrmbl_req_bundle.data ),
+ .valid_i ( scrmbl_req_bundle.valid ),
+ .ready_o ( scrmbl_arb_req_ready ),
+ .data_o ( part_scrmbl_rsp_data ),
+ .valid_o ( scrmbl_arb_rsp_valid ),
+ .escalate_en_i ( lc_escalate_en_i ),
+ .fsm_err_o ( scrmbl_fsm_err )
);
// steer back responses
@@ -541,19 +567,67 @@
.otp_err_i ( part_otp_err )
);
- ///////////////////////////////
- // Scrambling Key Derivation //
- ///////////////////////////////
+ // Tie off unused connections.
+ assign part_scrmbl_mtx_req[LciIdx] = '0;
+ assign part_scrmbl_req_bundle[LciIdx] = '0;
- // TODO: scrambling key derivation datapath
- logic scrambling_keys_valid;
- logic [SramKeySeedWidth-1:0] sram_data_key;
- logic [FlashKeySeedWidth-1:0] flash_data_key, flash_addr_key;
+ // This stops lint from complaining about unused signals.
+ logic unused_part_scrmbl_req_ready, unused_part_scrmbl_rsp_valid, unused_part_scrmbl_mtx_gnt;
+ assign unused_part_scrmbl_mtx_gnt = part_scrmbl_mtx_gnt[LciIdx];
+ assign unused_part_scrmbl_req_ready = part_scrmbl_req_ready[LciIdx];
+ assign unused_part_scrmbl_rsp_valid = part_scrmbl_rsp_valid[LciIdx];
- // TODO: add all key outputs
- assign otp_flash_key_o = '0;
- // TODO: hashed raw unlock token
- assign lc_otp_token_rsp_o = '0;
+ ////////////////////////////////////
+ // Key Derivation Interface (KDI) //
+ ////////////////////////////////////
+
+ logic scrmbl_key_seed_valid;
+ logic [SramKeySeedWidth-1:0] sram_data_key_seed;
+ logic [FlashKeySeedWidth-1:0] flash_data_key_seed, flash_addr_key_seed;
+
+ otp_ctrl_kdi i_otp_ctrl_kdi (
+ .clk_i,
+ .rst_ni,
+ .key_deriv_en_i ( pwr_otp_init_rsp_o.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,
+ .lc_otp_token_req_i ,
+ .lc_otp_token_rsp_o ,
+ .flash_otp_key_req_i,
+ .flash_otp_key_rsp_o,
+ .sram_otp_key_req_i,
+ .sram_otp_key_rsp_o,
+ .otbn_otp_key_req_i,
+ .otbn_otp_key_rsp_o,
+ .scrmbl_mtx_req_o ( part_scrmbl_mtx_req[KdiIdx] ),
+ .scrmbl_mtx_gnt_i ( part_scrmbl_mtx_gnt[KdiIdx] ),
+ .scrmbl_cmd_o ( part_scrmbl_req_bundle[KdiIdx].cmd ),
+ .scrmbl_sel_o ( part_scrmbl_req_bundle[KdiIdx].sel ),
+ .scrmbl_data_o ( part_scrmbl_req_bundle[KdiIdx].data ),
+ .scrmbl_valid_o ( part_scrmbl_req_bundle[KdiIdx].valid ),
+ .scrmbl_ready_i ( part_scrmbl_req_ready[KdiIdx] ),
+ .scrmbl_valid_i ( part_scrmbl_rsp_valid[KdiIdx] ),
+ .scrmbl_data_i ( part_scrmbl_rsp_data )
+ );
+
+ // Tie off OTP bus access, since this is not needed.
+ assign part_otp_arb_req[KdiIdx] = 1'b0;
+ assign part_otp_arb_bundle[KdiIdx] = '0;
+
+ // This stops lint from complaining about unused signals.
+ logic unused_part_otp_arb_gnt, unused_part_otp_rvalid;
+ logic [OtpIfWidth-1:0] unused_part_otp_rdata;
+ logic [OtpErrWidth-1:0] unused_part_otp_err;
+ assign unused_part_otp_arb_gnt = part_otp_arb_gnt[KdiIdx];
+ assign unused_part_otp_rvalid = part_otp_rvalid[KdiIdx];
+ assign unused_part_otp_rdata = part_otp_rdata[KdiIdx];
+ assign unused_part_otp_err = part_otp_err[KdiIdx];
/////////////////////////
// Partition Instances //
@@ -619,8 +693,8 @@
.clk_i,
.rst_ni,
// TODO: Entropy for clearing LFSRs
- // .entropy_en_i ( entropy_i.en ),
- // .entropy_i ( entropy_i.data[(k-NumUnbuffered) * 2 +: 2] ),
+ // .entropy_en_i ( edn_otp_up_i.en ),
+ // .entropy_i ( edn_otp_up_i.data[(k-NumUnbuffered) * 2 +: 2] ),
.init_req_i ( part_init_req ),
.init_done_o ( part_init_done[k] ),
.integ_chk_req_i ( integ_chk_req[k] ),
@@ -662,6 +736,8 @@
// Buffered Data Output Mapping //
//////////////////////////////////
+ // TODO: template these mappings, based on the address map hjson contents.
+
// Output complete hardware config partition.
// Actual mapping to other IPs can occur at the top-level.
assign hw_cfg_o = part_buf_data[PartInfo[HwCfgIdx].offset +:
@@ -673,12 +749,12 @@
otp_keymgr_key_o.key_share0} = part_buf_data[PartInfo[Secret2Idx].offset +:
2*KeyMgrKeyWidth/8];
// Scrambling Keys
- assign scrambling_keys_valid = part_init_done[Secret1Idx];
- assign {sram_data_key,
- flash_data_key,
- flash_addr_key} = part_buf_data[PartInfo[Secret1Idx].offset +:
- 2*FlashKeySeedWidth/8 +
- SramKeySeedWidth/8];
+ assign scrmbl_key_seed_valid = part_init_done[Secret1Idx];
+ assign {sram_data_key_seed,
+ flash_data_key_seed,
+ flash_addr_key_seed} = part_buf_data[PartInfo[Secret1Idx].offset +:
+ 2*FlashKeySeedWidth/8 +
+ SramKeySeedWidth/8];
// Test unlock and exit tokens
assign otp_lc_data_o.test_token_valid = part_init_done[Secret0Idx];
assign {otp_lc_data_o.test_exit_token,
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv
new file mode 100644
index 0000000..16cb7b3
--- /dev/null
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv
@@ -0,0 +1,59 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Scrambling key derivation module for OTP.
+//
+
+`include "prim_assert.sv"
+
+module otp_ctrl_kdi
+ import otp_ctrl_pkg::*;
+ import otp_ctrl_reg_pkg::*;
+#(
+ // Number of SRAM key requestor slots. All of them will use the same key seed.
+ // However, each request will generate a new key seed.
+ parameter int NumSramKeyReqSlots = 3
+) (
+ input clk_i,
+ input rst_ni,
+ // Pulse to enable this module after OTP partitions have
+ // been initialized.
+ input key_deriv_en_i,
+ // Escalation input. This moves the FSM into a terminal state.
+ input lc_tx_t escalate_en_i,
+ // FSM is in error state
+ output otp_err_e fsm_err_o,
+ // Key seed inputs from OTP
+ input logic scrmbl_key_seed_valid_i,
+ input logic [FlashKeySeedWidth-1:0] flash_data_key_seed_i,
+ 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,
+ // 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,
+ // Scrambling key requests
+ input flash_otp_key_req_t flash_otp_key_req_i,
+ output flash_otp_key_rsp_t flash_otp_key_rsp_o,
+ input sram_otp_key_req_t [NumSramKeyReqSlots-1:0] sram_otp_key_req_i,
+ output sram_otp_key_rsp_t [NumSramKeyReqSlots-1:0] sram_otp_key_rsp_o,
+ input otbn_otp_key_req_t otbn_otp_key_req_i,
+ output otbn_otp_key_rsp_t otbn_otp_key_rsp_o,
+ // Scrambling mutex request
+ output logic scrmbl_mtx_req_o,
+ input scrmbl_mtx_gnt_i,
+ // Scrambling datapath interface
+ output otp_scrmbl_cmd_e scrmbl_cmd_o,
+ output logic [ConstSelWidth-1:0] scrmbl_sel_o,
+ output logic [ScrmblBlockWidth-1:0] scrmbl_data_o,
+ output logic scrmbl_valid_o,
+ input logic scrmbl_ready_i,
+ input logic scrmbl_valid_i,
+ input logic [ScrmblBlockWidth-1:0] scrmbl_data_i
+);
+
+
+endmodule : otp_ctrl_kdi
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 458ab35..34aabee 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv
@@ -53,7 +53,9 @@
output logic [NumPart-1:0] cnsty_chk_req_o, // request to all partitions
input [NumPart-1:0] integ_chk_ack_i, // response from partitions
input [NumPart-1:0] cnsty_chk_ack_i, // response from partitions
- output logic chk_timeout_o // a check has timed out
+ input lc_tx_t escalate_en_i, // escalation input, moves FSM into ErrorSt
+ output logic chk_timeout_o, // a check has timed out
+ output logic fsm_err_o // the FSM has reached an invalid state
);
//////////
@@ -153,9 +155,13 @@
IdleSt = 9'b011011101,
IntegWaitSt = 9'b100111111,
CnstyWaitSt = 9'b001000110,
- ErrSt = 9'b101101000
+ ErrorSt = 9'b101101000
} state_e;
+
state_e state_d, state_q;
+ logic chk_timeout_d, chk_timeout_q;
+
+ assign chk_timeout_o = chk_timeout_q;
always_comb begin : p_fsm
state_d = state_q;
@@ -174,6 +180,7 @@
// Status signals going to CSRs and error logic.
chk_timeout_o = 1'b0;
chk_pending_o = 1'b0;
+ fsm_err_o = 1'b0;
unique case (state_q)
///////////////////////////////////////////////////////////////////
@@ -206,7 +213,8 @@
IntegWaitSt: begin
chk_pending_o = 1'b1;
if (!timeout_zero && integ_cnt_zero) begin
- state_d = ErrSt;
+ state_d = ErrorSt;
+ chk_timeout_d = 1'b1;
end else if (integ_chk_req_q == '0) begin
state_d = IdleSt;
// This draws the next wait period.
@@ -221,7 +229,8 @@
CnstyWaitSt: begin
chk_pending_o = 1'b1;
if (!timeout_zero && cnsty_cnt_zero) begin
- state_d = ErrSt;
+ state_d = ErrorSt;
+ chk_timeout_d = 1'b1;
end else if (cnsty_chk_req_q == '0) begin
state_d = IdleSt;
// This draws the next wait period.
@@ -231,17 +240,26 @@
end
///////////////////////////////////////////////////////////////////
// Terminal error state. This raises an alert.
- ErrSt: begin
- chk_timeout_o = 1'b1;
+ ErrorSt: begin
+ if (!chk_timeout_q) begin
+ fsm_err_o = 1'b1;
+ end
end
///////////////////////////////////////////////////////////////////
// This should never happen, hence we directly jump into the
// error state, where an alert will be triggered.
default: begin
- state_d = ErrSt;
+ state_d = ErrorSt;
end
///////////////////////////////////////////////////////////////////
- endcase
+ endcase // state_q
+
+ if (state_q != ErrorSt) begin
+ // Unconditionally jump into the terminal error state in case of escalation.
+ if (escalate_en_i != Off) begin
+ state_d = ErrorSt;
+ end
+ end
end
///////////////
@@ -255,12 +273,14 @@
cnsty_cnt_q <= '0;
integ_chk_req_q <= '0;
cnsty_chk_req_q <= '0;
+ chk_timeout_q <= 1'b0;
end else begin
state_q <= state_d;
integ_cnt_q <= integ_cnt_d;
cnsty_cnt_q <= cnsty_cnt_d;
integ_chk_req_q <= integ_chk_req_d;
cnsty_chk_req_q <= cnsty_chk_req_d;
+ chk_timeout_q <= chk_timeout_d;
end
end
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv
index b4b2f67..6312855 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv
@@ -611,17 +611,23 @@
////////////////
// Known assertions
- `ASSERT_KNOWN(InitDoneKnown_A, init_done_o)
- `ASSERT_KNOWN(ErrorKnown_A, error_o)
- `ASSERT_KNOWN(AccessKnown_A, access_o)
- `ASSERT_KNOWN(DataKnown_A, data_o)
- `ASSERT_KNOWN(DigestKnown_A, digest_o)
-
- `ASSERT_KNOWN(OtpReqKnown_A, otp_req_o)
- `ASSERT_KNOWN(OtpCmdKnown_A, otp_cmd_o)
- `ASSERT_KNOWN(OtpSizeKnown_A, otp_size_o)
- `ASSERT_KNOWN(OtpWdataKnown_A, otp_wdata_o)
- `ASSERT_KNOWN(OtpAddrKnown_A, otp_addr_o)
+ `ASSERT_KNOWN(InitDoneKnown_A, init_done_o)
+ `ASSERT_KNOWN(IntegChkAckKnown_A, integ_chk_ack_o)
+ `ASSERT_KNOWN(CnstyChkAckKnown_A, cnsty_chk_ack_o)
+ `ASSERT_KNOWN(ErrorKnown_A, error_o)
+ `ASSERT_KNOWN(AccessKnown_A, access_o)
+ `ASSERT_KNOWN(DigestKnown_A, digest_o)
+ `ASSERT_KNOWN(DataKnown_A, data_o)
+ `ASSERT_KNOWN(OtpReqKnown_A, otp_req_o)
+ `ASSERT_KNOWN(OtpCmdKnown_A, otp_cmd_o)
+ `ASSERT_KNOWN(OtpSizeKnown_A, otp_size_o)
+ `ASSERT_KNOWN(OtpWdataKnown_A, otp_wdata_o)
+ `ASSERT_KNOWN(OtpAddrKnown_A, otp_addr_o)
+ `ASSERT_KNOWN(ScrmblMtxReqKnown_A, scrmbl_mtx_req_o)
+ `ASSERT_KNOWN(ScrmblCmdKnown_A, scrmbl_cmd_o)
+ `ASSERT_KNOWN(ScrmblSelKnown_A, scrmbl_sel_o)
+ `ASSERT_KNOWN(ScrmblDataKnown_A, scrmbl_data_o)
+ `ASSERT_KNOWN(ScrmblValidKnown_A, scrmbl_valid_o)
// Uninitialized partitions should always be locked, no matter what.
`ASSERT(InitWriteLocksPartition_A,
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_pkg.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_pkg.sv
index 1c5413c..dbebbb8 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_pkg.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_pkg.sv
@@ -176,29 +176,44 @@
'{Buffered, 11'h7A8, 88, 0, 1'b0, 1'b0, 1'b0, 1'b0}
};
- parameter int CreatorSwCfgIdx = 0;
- parameter int OwnerSwCfgIdx = 1;
- parameter int HwCfgIdx = 2;
- parameter int Secret0Idx = 3;
- parameter int Secret1Idx = 4;
- parameter int Secret2Idx = 5;
- parameter int LifeCycleIdx = 6;
- // These are not "real partitions", but in terms of implementation it is convenient to
- // add these at the end of certain arrays.
- parameter int DaiIdx = 7;
- parameter int LciIdx = 8;
+ typedef enum {
+ CreatorSwCfgIdx,
+ OwnerSwCfgIdx,
+ HwCfgIdx,
+ Secret0Idx,
+ Secret1Idx,
+ Secret2Idx,
+ LifeCycleIdx,
+ // These are not "real partitions", but in terms of implementation it is convenient to
+ // add these at the end of certain arrays.
+ DaiIdx,
+ LciIdx,
+ KdiIdx,
+ // Number of agents is the last idx+1.
+ NumAgents
+ } part_idx_e;
- parameter int NumUnbuffered = 2;
parameter int NumHwCfgBits = PartInfo[HwCfgIdx].size*8;
////////////////////////
// Typedefs for CSRNG //
////////////////////////
+ // Unidirectional input type for LFSR reseeding.
typedef struct packed {
logic en;
logic [31:0] data;
- } otp_entropy_t;
+ } edn_otp_up_t;
+
+ // Bidirectional entropy requests for scramble key derivation.
+ typedef struct packed {
+ logic req;
+ } otp_edn_req_t;
+
+ typedef struct packed {
+ logic ack;
+ logic [31:0] data;
+ } otp_edn_rsp_t;
///////////////////////////////
// Typedefs for LC Interface //
@@ -212,8 +227,8 @@
parameter int NumLcCountValues = 32;
typedef enum logic [LcValueWidth-1:0] {
- Blk = 16'h0000,
- Set = 16'hF5FA
+ Blk = 16'h0000, // blank
+ Set = 16'hF5FA // programmed
} lc_value_e;
typedef enum logic [LcStateWidth-1:0] {
@@ -284,30 +299,57 @@
// Typedefs for Key Broadcast //
////////////////////////////////
- parameter int KeyMgrKeyWidth = 256;
- parameter int FlashKeyWidth = 128;
- parameter int SramKeyWidth = 128;
-
parameter int FlashKeySeedWidth = 256;
parameter int SramKeySeedWidth = 128;
+ parameter int KeyMgrKeyWidth = 256;
+
+ parameter int FlashKeyWidth = 128;
+
+ parameter int SramKeyWidth = 128;
+ parameter int SramNonceWidth = 64;
+
+ parameter int OtbnKeyWidth = 128;
+ parameter int OtbnNonceWidth = 256;
+
typedef struct packed {
logic valid;
logic [KeyMgrKeyWidth-1:0] key_share0;
logic [KeyMgrKeyWidth-1:0] key_share1;
- } keymgr_key_t;
+ } otp_keymgr_key_t;
typedef struct packed {
- logic valid;
+ logic req;
+ } flash_otp_key_req_t;
+
+ typedef struct packed {
+ logic req;
+ } sram_otp_key_req_t;
+
+ typedef struct packed {
+ logic req;
+ } otbn_otp_key_req_t;
+
+ typedef struct packed {
+ logic ack;
logic [FlashKeyWidth-1:0] addr_key;
logic [FlashKeyWidth-1:0] data_key;
- } flash_key_t;
+ } flash_otp_key_rsp_t;
typedef struct packed {
- logic valid;
- logic [SramKeyWidth-1:0] addr_key;
- logic [SramKeyWidth-1:0] data_key;
- } sram_key_t;
+ logic ack;
+ logic [SramKeyWidth-1:0] key;
+ logic [SramNonceWidth-1:0] nonce;
+ } sram_otp_key_rsp_t;
+
+ typedef struct packed {
+ logic ack;
+ logic [OtbnKeyWidth-1:0] key;
+ logic [OtbnNonceWidth-1:0] nonce;
+ } otbn_otp_key_rsp_t;
+
+
+
////////////////////////////////
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv
index 39f270d..6c9a428 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv
@@ -77,7 +77,10 @@
output logic ready_o,
// output data
output logic [ScrmblBlockWidth-1:0] data_o,
- output logic valid_o
+ output logic valid_o,
+ // escalation input and FSM error indication
+ input logic escalate_en_i,
+ output logic fsm_err_o
);
////////////////////////
@@ -172,7 +175,7 @@
// FSM //
/////////
- // Encoding generated with ./sparse-fsm-encode -d 5 -m 4 -n 8
+ // Encoding generated with ./sparse-fsm-encode -d 5 -m 5 -n 9
// Hamming distance histogram:
//
// 0: --
@@ -180,19 +183,21 @@
// 2: --
// 3: --
// 4: --
- // 5: |||||||||||||||||||| (66.67%)
- // 6: |||||||||| (33.33%)
+ // 5: |||||||||||||||||||| (60.00%)
+ // 6: ||||||||||||| (40.00%)
// 7: --
// 8: --
+ // 9: --
//
// Minimum Hamming distance: 5
// Maximum Hamming distance: 6
//
- typedef enum logic [7:0] {
- IdleSt = 8'b11100001,
- DecryptSt = 8'b01011010,
- EncryptSt = 8'b10010100,
- DigestSt = 8'b00101111
+ typedef enum logic [8:0] {
+ IdleSt = 9'b011110111,
+ DecryptSt = 9'b000010001,
+ EncryptSt = 9'b011101000,
+ DigestSt = 9'b100111100,
+ ErrorSt = 9'b101001111
} state_e;
localparam int CntWidth = $clog2(NumPresentRounds+1);
@@ -224,6 +229,7 @@
cnt_clr = 1'b0;
valid_d = 1'b0;
ready_o = 1'b0;
+ fsm_err_o = 1'b0;
unique case (state_q)
///////////////////////////////////////////////////////////////////
@@ -329,12 +335,25 @@
end
end
///////////////////////////////////////////////////////////////////
+ // Terminal error state. This raises an alert.
+ ErrorSt: begin
+ fsm_err_o = 1'b1;
+ end
+ ///////////////////////////////////////////////////////////////////
+ // This should never happen, hence we directly jump into the
+ // error state, where an alert will be triggered.
default: begin
- // TODO: add error signal here as well, like in the partition controllers?
- state_d = IdleSt;
+ state_d = ErrorSt;
end
///////////////////////////////////////////////////////////////////
endcase // state_q
+
+ if (state_q != ErrorSt) begin
+ // Unconditionally jump into the terminal error state in case of escalation.
+ if (escalate_en_i != Off) begin
+ state_d = ErrorSt;
+ end
+ end
end
/////////////////////////////