[lc_ctrl] Add initial markdown shell and hjson
This allows us to reference and link to life-cycle collateral.
Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/Makefile b/hw/Makefile
index 95d9208..51f6bbe9 100644
--- a/hw/Makefile
+++ b/hw/Makefile
@@ -19,6 +19,7 @@
kmac \
i2c \
keymgr \
+ lc_ctrl \
nmi_gen \
otp_ctrl \
padctrl \
diff --git a/hw/ip/lc_ctrl/data/lc_ctrl.hjson b/hw/ip/lc_ctrl/data/lc_ctrl.hjson
new file mode 100644
index 0000000..11c94d1
--- /dev/null
+++ b/hw/ip/lc_ctrl/data/lc_ctrl.hjson
@@ -0,0 +1,63 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+{ name: "lc_ctrl",
+ clock_primary: "clk_i",
+ bus_device: "tlul",
+ bus_host: "none",
+
+// ///////////////////////////
+// // Interrupts and Alerts //
+// ///////////////////////////
+//
+// interrupt_list: [
+// ],
+//
+// alert_list: [
+// ],
+//
+// ////////////////
+// // Parameters //
+// ////////////////
+// param_list: [
+// ]
+//
+// /////////////////////////////
+// // Intermodule Connections //
+// /////////////////////////////
+// // TODO: these need to be refined during implementation and integration
+// inter_signal_list: [
+// ] // inter_signal_list
+
+ ///////////////
+ // Registers //
+ ///////////////
+
+ regwidth: "32",
+ registers: [
+ { name: "STATUS",
+ desc: "LC status register.",
+ swaccess: "ro",
+ hwaccess: "hwo",
+ fields: [
+ { bits: "1:0"
+ name: "DUMMY"
+ desc: '''foo
+ '''
+ }
+ ]
+ }
+ { name: "CTRL",
+ desc: "LC control register.",
+ swaccess: "ro",
+ hwaccess: "hwo",
+ fields: [
+ { bits: "1:0"
+ name: "DUMMY"
+ desc: '''foo
+ '''
+ }
+ ]
+ }
+ ]
+}
diff --git a/hw/ip/lc_ctrl/data/lc_ctrl.prj.hjson b/hw/ip/lc_ctrl/data/lc_ctrl.prj.hjson
new file mode 100644
index 0000000..89cafe2
--- /dev/null
+++ b/hw/ip/lc_ctrl/data/lc_ctrl.prj.hjson
@@ -0,0 +1,15 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+{
+ name: "lc_ctrl",
+ design_spec: "hw/ip/lc_ctrl/doc",
+ dv_plan: "",
+ hw_checklist: "",
+ version: "0.1",
+ life_stage: "L0",
+ design_stage: "D0",
+ verification_stage: "V0",
+ notes: "",
+}
diff --git a/hw/ip/lc_ctrl/doc/_index.md b/hw/ip/lc_ctrl/doc/_index.md
new file mode 100644
index 0000000..0edd27c
--- /dev/null
+++ b/hw/ip/lc_ctrl/doc/_index.md
@@ -0,0 +1,34 @@
+---
+title: "Life Cycle Controller Technical Specification"
+---
+
+
+# Overview
+
+**TODO: populate with spec text. this is an empty shell to be able to link to from other docs.**
+
+## Features
+
+## Life Cycle Controller Overview
+
+# Theory of Operations
+
+## Hardware Interfaces
+
+### Parameters
+
+Parameter | Default (Max) | Top Earlgrey | Description
+----------------------------|-----------------------|--------------|---------------
+
+### Signals
+
+{{< hwcfg "hw/ip/lc_ctrl/data/lc_ctrl.hjson" >}}
+
+Signal | Direction | Type | Description
+-------------------------|------------------|-----------------------------|---------------
+
+
+## Register Table
+
+{{< registers "hw/ip/lc_ctrl/data/lc_ctrl.hjson" >}}
+
diff --git a/hw/ip/lc_ctrl/lc_ctrl_pkg.core b/hw/ip/lc_ctrl/lc_ctrl_pkg.core
new file mode 100644
index 0000000..09d879f
--- /dev/null
+++ b/hw/ip/lc_ctrl/lc_ctrl_pkg.core
@@ -0,0 +1,21 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:ip:lc_ctrl_pkg:0.1"
+description: "LC Controller Package"
+filesets:
+ files_rtl:
+ depend:
+ - lowrisc:tlul:headers
+
+ files:
+ - rtl/lc_ctrl_reg_pkg.sv
+ - rtl/lc_ctrl_pkg.sv
+ file_type: systemVerilogSource
+
+
+targets:
+ default: &default_target
+ filesets:
+ - files_rtl
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
new file mode 100644
index 0000000..36a78ef
--- /dev/null
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
@@ -0,0 +1,56 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+
+package lc_ctrl_pkg;
+
+ /////////////////////////////////
+ // General Typedefs and Params //
+ /////////////////////////////////
+
+ parameter int LcValueWidth = 16;
+ parameter int LcTokenWidth = 128;
+ parameter int NumLcStateValues = 12;
+ parameter int LcStateWidth = NumLcStateValues * LcValueWidth;
+ parameter int NumLcCountValues = 32;
+
+ typedef enum logic [LcValueWidth-1:0] {
+ Blk = 16'h0000, // blank
+ Set = 16'hF5FA // programmed
+ } lc_value_e;
+
+ typedef enum logic [LcStateWidth-1:0] {
+ // Halfword idx : 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
+ LcStRaw = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk},
+ LcStTestUnlocked0 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set},
+ LcStTestLocked0 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set},
+ LcStTestUnlocked1 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set},
+ LcStTestLocked1 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set},
+ LcStTestUnlocked2 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set},
+ LcStTestLocked2 = {Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set, Set},
+ LcStTestUnlocked3 = {Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set, Set, Set},
+ LcStDev = {Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set, Set, Set, Set},
+ LcStProd = {Blk, Blk, Blk, Set, Blk, Set, Set, Set, Set, Set, Set, Set},
+ LcStProdEnd = {Blk, Blk, Set, Blk, Blk, Set, Set, Set, Set, Set, Set, Set},
+ LcStRma = {Set, Set, Blk, Set, Set, Set, Set, Set, Set, Set, Set, Set},
+ LcStScrap = {Set, Set, Set, Set, Set, Set, Set, Set, Set, Set, Set, Set}
+ } lc_state_e;
+
+ typedef lc_value_e [NumLcCountValues-1:0] lc_cnt_t;
+
+ ////////////////////////////////
+ // Typedefs for LC Interfaces //
+ ////////////////////////////////
+
+ typedef enum logic [2:0] {
+ On = 3'b101,
+ Off = 3'b000
+ } lc_tx_e;
+
+ typedef struct packed {
+ lc_tx_e state;
+ } lc_tx_t;
+
+
+endpackage : lc_ctrl_pkg
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_pkg.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_pkg.sv
new file mode 100644
index 0000000..696b4bd
--- /dev/null
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_pkg.sv
@@ -0,0 +1,53 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Package auto-generated by `reggen` containing data structure
+
+package lc_ctrl_reg_pkg;
+
+ ////////////////////////////
+ // Typedefs for registers //
+ ////////////////////////////
+
+ typedef struct packed {
+ logic [1:0] d;
+ logic de;
+ } lc_ctrl_hw2reg_status_reg_t;
+
+ typedef struct packed {
+ logic [1:0] d;
+ logic de;
+ } lc_ctrl_hw2reg_ctrl_reg_t;
+
+
+ ///////////////////////////////////////
+ // Register to internal design logic //
+ ///////////////////////////////////////
+
+ ///////////////////////////////////////
+ // Internal design logic to register //
+ ///////////////////////////////////////
+ typedef struct packed {
+ lc_ctrl_hw2reg_status_reg_t status; // [5:6]
+ lc_ctrl_hw2reg_ctrl_reg_t ctrl; // [5:6]
+ } lc_ctrl_hw2reg_t;
+
+ // Register Address
+ parameter logic [2:0] LC_CTRL_STATUS_OFFSET = 3'h 0;
+ parameter logic [2:0] LC_CTRL_CTRL_OFFSET = 3'h 4;
+
+
+ // Register Index
+ typedef enum int {
+ LC_CTRL_STATUS,
+ LC_CTRL_CTRL
+ } lc_ctrl_id_e;
+
+ // Register width information to check illegal writes
+ parameter logic [3:0] LC_CTRL_PERMIT [2] = '{
+ 4'b 0001, // index[0] LC_CTRL_STATUS
+ 4'b 0001 // index[1] LC_CTRL_CTRL
+ };
+endpackage
+
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_top.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_top.sv
new file mode 100644
index 0000000..40dcded
--- /dev/null
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_top.sv
@@ -0,0 +1,179 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Top module auto-generated by `reggen`
+
+`include "prim_assert.sv"
+
+module lc_ctrl_reg_top (
+ input clk_i,
+ input rst_ni,
+
+ // Below Regster interface can be changed
+ input tlul_pkg::tl_h2d_t tl_i,
+ output tlul_pkg::tl_d2h_t tl_o,
+ // To HW
+ input lc_ctrl_reg_pkg::lc_ctrl_hw2reg_t hw2reg, // Read
+
+ // Config
+ input devmode_i // If 1, explicit error return for unmapped register access
+);
+
+ import lc_ctrl_reg_pkg::* ;
+
+ localparam int AW = 3;
+ localparam int DW = 32;
+ localparam int DBW = DW/8; // Byte Width
+
+ // register signals
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
+
+ logic addrmiss, wr_err;
+
+ logic [DW-1:0] reg_rdata_next;
+
+ tlul_pkg::tl_h2d_t tl_reg_h2d;
+ tlul_pkg::tl_d2h_t tl_reg_d2h;
+
+ assign tl_reg_h2d = tl_i;
+ assign tl_o = tl_reg_d2h;
+
+ tlul_adapter_reg #(
+ .RegAw(AW),
+ .RegDw(DW)
+ ) u_reg_if (
+ .clk_i,
+ .rst_ni,
+
+ .tl_i (tl_reg_h2d),
+ .tl_o (tl_reg_d2h),
+
+ .we_o (reg_we),
+ .re_o (reg_re),
+ .addr_o (reg_addr),
+ .wdata_o (reg_wdata),
+ .be_o (reg_be),
+ .rdata_i (reg_rdata),
+ .error_i (reg_error)
+ );
+
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = (devmode_i & addrmiss) | wr_err ;
+
+ // Define SW related signals
+ // Format: <reg>_<field>_{wd|we|qs}
+ // or <reg>_{wd|we|qs} if field == 1 or 0
+ logic [1:0] status_qs;
+ logic [1:0] ctrl_qs;
+
+ // Register instances
+ // R[status]: V(False)
+
+ prim_subreg #(
+ .DW (2),
+ .SWACCESS("RO"),
+ .RESVAL (2'h0)
+ ) u_status (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ .we (1'b0),
+ .wd ('0 ),
+
+ // from internal hardware
+ .de (hw2reg.status.de),
+ .d (hw2reg.status.d ),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+
+ // to register interface (read)
+ .qs (status_qs)
+ );
+
+
+ // R[ctrl]: V(False)
+
+ prim_subreg #(
+ .DW (2),
+ .SWACCESS("RO"),
+ .RESVAL (2'h0)
+ ) u_ctrl (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ .we (1'b0),
+ .wd ('0 ),
+
+ // from internal hardware
+ .de (hw2reg.ctrl.de),
+ .d (hw2reg.ctrl.d ),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+
+ // to register interface (read)
+ .qs (ctrl_qs)
+ );
+
+
+
+
+ logic [1:0] addr_hit;
+ always_comb begin
+ addr_hit = '0;
+ addr_hit[0] = (reg_addr == LC_CTRL_STATUS_OFFSET);
+ addr_hit[1] = (reg_addr == LC_CTRL_CTRL_OFFSET);
+ end
+
+ assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
+
+ // Check sub-word write is permitted
+ always_comb begin
+ wr_err = 1'b0;
+ if (addr_hit[0] && reg_we && (LC_CTRL_PERMIT[0] != (LC_CTRL_PERMIT[0] & reg_be))) wr_err = 1'b1 ;
+ if (addr_hit[1] && reg_we && (LC_CTRL_PERMIT[1] != (LC_CTRL_PERMIT[1] & reg_be))) wr_err = 1'b1 ;
+ end
+
+
+
+ // Read data return
+ always_comb begin
+ reg_rdata_next = '0;
+ unique case (1'b1)
+ addr_hit[0]: begin
+ reg_rdata_next[1:0] = status_qs;
+ end
+
+ addr_hit[1]: begin
+ reg_rdata_next[1:0] = ctrl_qs;
+ end
+
+ default: begin
+ reg_rdata_next = '1;
+ end
+ endcase
+ end
+
+ // Assertions for Register Interface
+ `ASSERT_PULSE(wePulse, reg_we)
+ `ASSERT_PULSE(rePulse, reg_re)
+
+ `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+
+ `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+
+ // this is formulated as an assumption such that the FPV testbenches do disprove this
+ // property by mistake
+ `ASSUME(reqParity, tl_reg_h2d.a_valid |-> tl_reg_h2d.a_user.parity_en == 1'b0)
+
+endmodule
diff --git a/hw/ip/otp_ctrl/otp_ctrl_pkg.core b/hw/ip/otp_ctrl/otp_ctrl_pkg.core
index 02da53b..c799c9e 100644
--- a/hw/ip/otp_ctrl/otp_ctrl_pkg.core
+++ b/hw/ip/otp_ctrl/otp_ctrl_pkg.core
@@ -8,6 +8,7 @@
files_rtl:
depend:
- lowrisc:tlul:headers
+ - lowrisc:ip:lc_ctrl_pkg
files:
- rtl/otp_ctrl_reg_pkg.sv
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
index c085117..ec8f431 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
@@ -33,7 +33,7 @@
input rst_ni,
// Macro-specific power sequencing signals to/from AST.
output otp_ast_req_t otp_ast_pwr_seq_o,
- input otp_ast_rsp_t otp_ast_pwr_seq_i,
+ input otp_ast_rsp_t otp_ast_pwr_seq_h_i,
// Bus Interface (device)
input tlul_pkg::tl_h2d_t tl_i,
output tlul_pkg::tl_d2h_t tl_o,
@@ -56,9 +56,9 @@
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_ctrl_pkg::lc_tx_t lc_escalate_en_i,
+ input lc_ctrl_pkg::lc_tx_t lc_provision_en_i,
+ input lc_ctrl_pkg::lc_tx_t lc_dft_en_i,
// OTP broadcast outputs
output otp_lc_data_t otp_lc_data_o,
output otp_keymgr_key_t otp_keymgr_key_o,
@@ -134,8 +134,8 @@
// Propagate CSR read enables down to the SW_CFG partitions.
if (!reg2hw.creator_sw_cfg_read_lock) part_access_csrs[CreatorSwCfgIdx].read_lock = Locked;
if (!reg2hw.owner_sw_cfg_read_lock) part_access_csrs[OwnerSwCfgIdx].read_lock = Locked;
- // The SECRET2 partition can only be accessed when provisioning is enabled.
- if (lc_provision_en_i != On) part_access_csrs[Secret2Idx].read_lock = Locked;
+ // The SECRET2 partition can only be accessed (write&read) when provisioning is enabled.
+ if (lc_provision_en_i != lc_ctrl_pkg::On) part_access_csrs[Secret2Idx] = {2{Locked}};
// Permanently lock DAI write access to the life cycle partition
part_access_csrs[LifeCycleIdx].write_lock = Locked;
end
@@ -385,8 +385,10 @@
tlul_pkg::tl_d2h_t tl_win_d2h_gated;
// Life cycle qualification of TL-UL test interface.
- assign tl_win_h2d_gated = (lc_test_en_i == On) ? tl_win_h2d[$high(tl_win_h2d)] : '0;
- assign tl_win_d2h[$high(tl_win_h2d)] = (lc_test_en_i == On) ? tl_win_d2h_gated : '0;
+ assign tl_win_h2d_gated = (lc_dft_en_i == lc_ctrl_pkg::On) ?
+ tl_win_h2d[$high(tl_win_h2d)] : '0;
+ assign tl_win_d2h[$high(tl_win_h2d)] = (lc_dft_en_i == lc_ctrl_pkg::On) ?
+ tl_win_d2h_gated : '0;
prim_otp #(
.Width(OtpWidth),
@@ -395,8 +397,8 @@
.clk_i,
.rst_ni,
// Power sequencing signals to/from AST
- .pwr_seq_o ( otp_ast_pwr_seq_o.pwr_seq ),
- .pwr_seq_h_i ( otp_ast_pwr_seq_i.pwr_seq_h ),
+ .pwr_seq_o ( otp_ast_pwr_seq_o.pwr_seq ),
+ .pwr_seq_h_i ( otp_ast_pwr_seq_h_i.pwr_seq_h ),
// Test interface
.test_tl_i ( tl_win_h2d_gated ),
.test_tl_o ( tl_win_d2h_gated ),
@@ -455,6 +457,8 @@
// partition must yield its lock by deasserting the request signal for the arbiter to proceed.
// Since this scheme does not have built-in preemtion, it must be ensured that the agents
// eventually release their locks for this to be fair.
+ //
+ // See also https://docs.opentitan.org/hw/ip/otp_ctrl/doc/index.html#block-diagram for details.
typedef struct packed {
otp_scrmbl_cmd_e cmd;
logic [ConstSelWidth-1:0] sel;
@@ -575,24 +579,24 @@
) u_otp_ctrl_lci (
.clk_i,
.rst_ni,
- .lci_en_i ( pwr_otp_rsp_o.otp_done ),
- .escalate_en_i ( lc_escalate_en_i ),
- .error_o ( part_error[LciIdx] ),
- .lci_idle_o ( lci_idle ),
- .lc_req_i ( lc_otp_program_req_i.req ),
- .lc_state_diff_i ( lc_otp_program_req_i.state_diff ),
- .lc_count_diff_i ( lc_otp_program_req_i.count_diff ),
- .lc_ack_o ( lc_otp_program_rsp_o.ack ),
- .lc_err_o ( lc_otp_program_rsp_o.err ),
- .otp_req_o ( part_otp_arb_req[LciIdx] ),
- .otp_cmd_o ( part_otp_arb_bundle[LciIdx].cmd ),
- .otp_size_o ( part_otp_arb_bundle[LciIdx].size ),
- .otp_wdata_o ( part_otp_arb_bundle[LciIdx].wdata ),
- .otp_addr_o ( part_otp_arb_bundle[LciIdx].addr ),
- .otp_gnt_i ( part_otp_arb_gnt[LciIdx] ),
- .otp_rvalid_i ( part_otp_rvalid[LciIdx] ),
- .otp_rdata_i ( part_otp_rdata ),
- .otp_err_i ( part_otp_err )
+ .lci_en_i ( pwr_otp_rsp_o.otp_done ),
+ .escalate_en_i ( lc_escalate_en_i ),
+ .error_o ( part_error[LciIdx] ),
+ .lci_idle_o ( lci_idle ),
+ .lc_req_i ( lc_otp_program_req_i.req ),
+ .lc_state_delta_i ( lc_otp_program_req_i.state_delta ),
+ .lc_count_delta_i ( lc_otp_program_req_i.count_delta ),
+ .lc_ack_o ( lc_otp_program_rsp_o.ack ),
+ .lc_err_o ( lc_otp_program_rsp_o.err ),
+ .otp_req_o ( part_otp_arb_req[LciIdx] ),
+ .otp_cmd_o ( part_otp_arb_bundle[LciIdx].cmd ),
+ .otp_size_o ( part_otp_arb_bundle[LciIdx].size ),
+ .otp_wdata_o ( part_otp_arb_bundle[LciIdx].wdata ),
+ .otp_addr_o ( part_otp_arb_bundle[LciIdx].addr ),
+ .otp_gnt_i ( part_otp_arb_gnt[LciIdx] ),
+ .otp_rvalid_i ( part_otp_rvalid[LciIdx] ),
+ .otp_rdata_i ( part_otp_rdata ),
+ .otp_err_i ( part_otp_err )
);
// Tie off unused connections.
@@ -780,24 +784,24 @@
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,
otp_lc_data_o.test_unlock_token} = part_buf_data[PartInfo[Secret0Idx].offset +:
- 2*LcTokenWidth/8];
+ 2*lc_ctrl_pkg::LcTokenWidth/8];
// RMA token
- assign otp_lc_data_o.rma_token_valid = part_init_done[Secret2Idx];
- assign otp_lc_data_o.rma_token = part_buf_data[PartInfo[Secret2Idx].offset +:
- LcTokenWidth/8];
+ assign otp_lc_data_o.rma_token = part_buf_data[PartInfo[Secret2Idx].offset +:
+ lc_ctrl_pkg::LcTokenWidth/8];
// The device is personalized if the root key has been provisioned and locked
- assign otp_lc_data_o.id_state_valid = part_init_done[Secret2Idx];
- assign otp_lc_data_o.id_state = (part_digest[Secret2Idx] != '0) ? Set : Blk;
+ assign otp_lc_data_o.id_state = (part_digest[Secret2Idx] != '0) ? lc_ctrl_pkg::Set :
+ lc_ctrl_pkg::Blk;
// Lifecycle state
- assign otp_lc_data_o.state_valid = part_init_done[LifeCycleIdx];
assign {otp_lc_data_o.count,
otp_lc_data_o.state} = part_buf_data[PartInfo[LifeCycleIdx].offset +:
PartInfo[LifeCycleIdx].size];
+ // Assert life cycle state valid signal only when all partitions have initialized.
+ assign otp_lc_data_o.valid = &part_init_done;
+
// Not all bits of part_buf_data are used here.
logic unused_buf_data;
assign unused_buf_data = ^part_buf_data;
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv
index daf7cd9..96497c7 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv
@@ -21,7 +21,7 @@
input [NumPart-1:0] part_init_done_i,
// Escalation input. This moves the FSM into a terminal state and locks down
// the DAI.
- input lc_tx_t escalate_en_i,
+ input lc_ctrl_pkg::lc_tx_t escalate_en_i,
// Output error state of DAI, to be consumed by OTP error/alert logic.
// Note that most errors are not recoverable and move the DAI FSM into
// a terminal error state.
@@ -546,11 +546,10 @@
///////////////////////////////////////////////////////////////////
endcase // state_q
- if (state_q != ErrorSt) begin
- // Unconditionally jump into the terminal error state in case of
- // escalation, and lock access to the DAI down.
- if (escalate_en_i != Off) begin
- state_d = ErrorSt;
+ // Unconditionally jump into the terminal error state in case of escalation.
+ if (escalate_en_i != lc_ctrl_pkg::Off) begin
+ state_d = ErrorSt;
+ if (state_q != ErrorSt) begin
error_d = EscErr;
end
end
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv
index 8e117fb..bbc05cb 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv
@@ -21,7 +21,7 @@
// been initialized.
input kdi_en_i,
// Escalation input. This moves the FSM into a terminal state.
- input lc_tx_t escalate_en_i,
+ input lc_ctrl_pkg::lc_tx_t escalate_en_i,
// FSM is in error state
output logic fsm_err_o,
// Key seed inputs from OTP
@@ -455,7 +455,7 @@
endcase // state_q
// Unconditionally jump into the terminal error state in case of escalation.
- if (escalate_en_i != Off) begin
+ if (escalate_en_i != lc_ctrl_pkg::Off) begin
state_d = ErrorSt;
end
end
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_lci.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_lci.sv
index 5e2c73c..741b81f 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_lci.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_lci.sv
@@ -19,14 +19,14 @@
input lci_en_i,
// Escalation input. This moves the FSM into a terminal state and locks down
// the partition.
- input lc_tx_t escalate_en_i,
+ input lc_ctrl_pkg::lc_tx_t escalate_en_i,
// Life cycle transition request. In order to perform a state transition,
- // the LC controller signals the differential value with respect to the
+ // the LC controller signals the incremental value with respect to the
// current state. The OTP controller then only programs the non-zero
- // state differential.
+ // state delta.
input lc_req_i,
- input lc_state_e lc_state_diff_i,
- input lc_value_e [NumLcCountValues-1:0] lc_count_diff_i,
+ input lc_ctrl_pkg::lc_state_e lc_state_delta_i,
+ input lc_ctrl_pkg::lc_cnt_t lc_count_delta_i,
output logic lc_ack_o,
output logic lc_err_o,
// Output error state of partition, to be consumed by OTP error/alert logic.
@@ -55,6 +55,9 @@
localparam int NumLcOtpWords = Info.size >> OtpAddrShift;
localparam int CntWidth = vbits(NumLcOtpWords);
+ // This is required, since each native OTP word can only be programmed once.
+ `ASSERT_INIT(LcValueMustBeWiderThanNativeOtpWidth_A, lc_ctrl_pkg::LcValueWidth >= OtpWidth)
+
////////////////////
// Controller FSM //
////////////////////
@@ -88,7 +91,7 @@
logic cnt_clr, cnt_en;
logic [CntWidth-1:0] cnt_d, cnt_q;
otp_err_e error_d, error_q;
- logic diff_data_is_set;
+ logic delta_data_is_set;
state_e state_d, state_q;
// Output LCI errors
@@ -135,7 +138,7 @@
// Loop through the lifecycle sate and burn in the words that are set.
WriteSt: begin
// Check whether the OTP word is nonzero.
- if (diff_data_is_set) begin
+ if (delta_data_is_set) begin
otp_req_o = 1'b1;
otp_cmd_o = OtpWrite;
if (otp_gnt_i) begin
@@ -195,10 +198,10 @@
///////////////////////////////////////////////////////////////////
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;
+ // Unconditionally jump into the terminal error state in case of escalation.
+ if (escalate_en_i != lc_ctrl_pkg::Off) begin
+ state_d = ErrorSt;
+ if (state_q != ErrorSt) begin
error_d = EscErr;
end
end
@@ -220,10 +223,10 @@
// Always transfer 16bit blocks.
assign otp_size_o = '0;
- logic [NumLcOtpWords-1:0][OtpWidth-1:0] diff_data;
- assign diff_data = {lc_count_diff_i, lc_state_diff_i};
- assign otp_wdata_o = OtpIfWidth'(diff_data[cnt_q]);
- assign diff_data_is_set = (diff_data[cnt_q] != Blk);
+ logic [NumLcOtpWords-1:0][OtpWidth-1:0] delta_data;
+ assign delta_data = {lc_count_delta_i, lc_state_delta_i};
+ assign otp_wdata_o = OtpIfWidth'(delta_data[cnt_q]);
+ assign delta_data_is_set = (delta_data[cnt_q] != lc_ctrl_pkg::Blk);
logic unused_rdata;
assign unused_rdata = ^otp_rdata_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 bef05c3..ab4ec6c 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv
@@ -56,7 +56,7 @@
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
- input lc_tx_t escalate_en_i, // escalation input, moves FSM into ErrorSt
+ input lc_ctrl_pkg::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
);
@@ -274,11 +274,9 @@
///////////////////////////////////////////////////////////////////
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
+ // Unconditionally jump into the terminal error state in case of escalation.
+ if (escalate_en_i != lc_ctrl_pkg::Off) begin
+ state_d = ErrorSt;
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 c11bc28..b1f77c6 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv
@@ -27,7 +27,7 @@
output logic cnsty_chk_ack_o,
// Escalation input. This moves the FSM into a terminal state and locks down
// the partition.
- input lc_tx_t escalate_en_i,
+ input lc_ctrl_pkg::lc_tx_t escalate_en_i,
// Output error state of partition, to be consumed by OTP error/alert logic.
// Note that most errors are not recoverable and move the partition FSM into
// a terminal error state.
@@ -504,15 +504,18 @@
///////////////////////////////////////////////////////////////////
endcase // state_q
- if (state_q != ErrorSt) begin
- // Unconditionally jump into the terminal error state in case of
- // a parity error or escalation, and lock access to the partition down.
- if (parity_err) begin
- state_d = ErrorSt;
+
+ // Unconditionally jump into the terminal error state in case of
+ // a parity error or escalation, and lock access to the partition down.
+ if (parity_err) begin
+ state_d = ErrorSt;
+ if (state_q != ErrorSt) begin
error_d = ParityErr;
end
- if (escalate_en_i != Off) begin
- state_d = ErrorSt;
+ end
+ if (escalate_en_i != lc_ctrl_pkg::Off) begin
+ state_d = ErrorSt;
+ if (state_q != ErrorSt) begin
error_d = EscErr;
end
end
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_unbuf.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_unbuf.sv
index 3661a1f..57a6088 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_unbuf.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_unbuf.sv
@@ -21,7 +21,7 @@
output logic init_done_o,
// Escalation input. This moves the FSM into a terminal state and locks down
// the partition.
- input lc_tx_t escalate_en_i,
+ input lc_ctrl_pkg::lc_tx_t escalate_en_i,
// Output error state of partition, to be consumed by OTP error/alert logic.
// Note that most errors are not recoverable and move the partition FSM into
// a terminal error state.
@@ -251,15 +251,17 @@
///////////////////////////////////////////////////////////////////
endcase // state_q
- if (state_q != ErrorSt) begin
- // Unconditionally jump into the terminal error state in case of
- // a parity error or escalation, and lock access to the partition down.
- if (parity_err) begin
- state_d = ErrorSt;
+ // Unconditionally jump into the terminal error state in case of
+ // a parity error or escalation, and lock access to the partition down.
+ if (parity_err) begin
+ state_d = ErrorSt;
+ if (state_q != ErrorSt) begin
error_d = ParityErr;
end
- if (escalate_en_i != Off) begin
- state_d = ErrorSt;
+ end
+ if (escalate_en_i != lc_ctrl_pkg::Off) begin
+ state_d = ErrorSt;
+ if (state_q != ErrorSt) begin
error_d = EscErr;
end
end
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_pkg.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_pkg.sv
index fd277be..4fe6be9 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_pkg.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_pkg.sv
@@ -231,51 +231,20 @@
// Typedefs for LC Interface //
///////////////////////////////
- // TODO: move all these definitions to the lc_ctrl_pkg
- parameter int LcValueWidth = OtpWidth;
- parameter int LcTokenWidth = 128;
- parameter int NumLcStateValues = 12;
- parameter int LcStateWidth = NumLcStateValues * LcValueWidth;
- parameter int NumLcCountValues = 32;
-
- typedef enum logic [LcValueWidth-1:0] {
- Blk = 16'h0000, // blank
- Set = 16'hF5FA // programmed
- } lc_value_e;
-
- typedef enum logic [LcStateWidth-1:0] {
- LcStRaw = {NumLcStateValues{Blk}},
- LcStTestUnlocked0 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set},
- LcStTestLocked0 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set},
- LcStTestUnlocked1 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set},
- LcStTestLocked1 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set},
- LcStTestUnlocked2 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set},
- LcStTestLocked2 = {Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set, Set},
- LcStTestUnlocked3 = {Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set, Set, Set},
- LcStDev = {Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set, Set, Set, Set},
- LcStProd = {Blk, Blk, Blk, Set, Blk, Set, Set, Set, Set, Set, Set, Set},
- LcStProdEnd = {Blk, Blk, Set, Blk, Blk, Set, Set, Set, Set, Set, Set, Set},
- LcStRma = {Set, Set, Blk, Set, Set, Set, Set, Set, Set, Set, Set, Set},
- LcStScrap = {NumLcStateValues{Set}}
- } lc_state_e;
-
typedef struct packed {
- logic state_valid;
- logic test_token_valid;
- logic rma_token_valid;
- logic id_state_valid;
- lc_state_e state;
- lc_value_e [NumLcCountValues-1:0] count;
- logic [LcTokenWidth-1:0] test_unlock_token;
- logic [LcTokenWidth-1:0] test_exit_token;
- logic [LcTokenWidth-1:0] rma_token;
- lc_value_e id_state;
+ logic valid;
+ lc_ctrl_pkg::lc_state_e state;
+ lc_ctrl_pkg::lc_cnt_t count;
+ logic [lc_ctrl_pkg::LcTokenWidth-1:0] test_unlock_token;
+ logic [lc_ctrl_pkg::LcTokenWidth-1:0] test_exit_token;
+ logic [lc_ctrl_pkg::LcTokenWidth-1:0] rma_token;
+ lc_ctrl_pkg::lc_value_e id_state;
} otp_lc_data_t;
typedef struct packed {
- logic req;
- lc_state_e state_diff;
- lc_value_e [NumLcCountValues-1:0] count_diff;
+ logic req;
+ lc_ctrl_pkg::lc_state_e state_delta;
+ lc_ctrl_pkg::lc_cnt_t count_delta;
} lc_otp_program_req_t;
typedef struct packed {
@@ -285,33 +254,15 @@
// RAW unlock token hashing request.
typedef struct packed {
- logic req;
- logic [LcTokenWidth-1:0] token_input;
+ logic req;
+ logic [lc_ctrl_pkg::LcTokenWidth-1:0] token_input;
} lc_otp_token_req_t;
typedef struct packed {
-<<<<<<< HEAD
- logic ack;
- logic [LcTokenWidth-1:0] hashed_token;
-=======
logic ack;
logic [lc_ctrl_pkg::LcTokenWidth-1:0] hashed_token;
->>>>>>> cd99a29a (fix)
} lc_otp_token_rsp_t;
-
- // TODO: move this to the LC ctrl package
- typedef enum logic [2:0] {
- On = 3'b101,
- Off = 3'b000
- } lc_tx_e;
-
- // TODO: move this to the LC ctrl package
- typedef struct packed {
- lc_tx_e state;
- } lc_tx_t;
-
-
////////////////////////////////
// Typedefs for Key Broadcast //
////////////////////////////////
@@ -366,7 +317,6 @@
logic [OtbnNonceWidth-1:0] nonce;
} otbn_otp_key_rsp_t;
-
////////////////////////////////
// Power/Reset Ctrl Interface //
////////////////////////////////
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv
index 509bfbf..5b48a5e 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv
@@ -79,7 +79,7 @@
output logic [ScrmblBlockWidth-1:0] data_o,
output logic valid_o,
// escalation input and FSM error indication
- input lc_tx_t escalate_en_i,
+ input lc_ctrl_pkg::lc_tx_t escalate_en_i,
output logic fsm_err_o
);
@@ -355,11 +355,9 @@
///////////////////////////////////////////////////////////////////
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
+ // Unconditionally jump into the terminal error state in case of escalation.
+ if (escalate_en_i != lc_ctrl_pkg::Off) begin
+ state_d = ErrorSt;
end
end