Skip to content

Commit

Permalink
[otp_ctrl] Add support for multiple HW_CFG partitions
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Schaffner <[email protected]>
  • Loading branch information
msfschaffner committed Jan 22, 2024
1 parent 4c8050f commit a59ca1b
Show file tree
Hide file tree
Showing 91 changed files with 518 additions and 445 deletions.
2 changes: 1 addition & 1 deletion BLOCKFILE
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ ci/scripts/check-pr-changes-allowed.py
# hw/ip/otp_ctrl/data/otp_ctrl_img_test_locked1.hjson
# hw/ip/otp_ctrl/data/otp_ctrl_img_test_unlocked0.hjson
# hw/ip/otp_ctrl/data/otp_ctrl_img_creator_sw_cfg.hjson
# hw/ip/otp_ctrl/data/otp_ctrl_img_hw_cfg.hjson
# hw/ip/otp_ctrl/data/otp_ctrl_img_hw_cfg0.hjson
# hw/ip/otp_ctrl/data/otp_ctrl_img_raw.hjson
# hw/ip/otp_ctrl/data/otp_ctrl_mmap.hjson
# hw/ip/otp_ctrl/data/otp_ctrl_img_test_unlocked1.hjson
Expand Down
20 changes: 10 additions & 10 deletions hw/dv/sv/mem_bkdr_util/mem_bkdr_util__otp.sv
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,15 @@ virtual function void otp_write_secret2_partition(bit [RmaTokenSize*8-1:0] rma_u
write64(Secret2DigestOffset, digest);
endfunction

virtual function void otp_write_hw_cfg_partition(
virtual function void otp_write_hw_cfg0_partition(
bit [DeviceIdSize*8-1:0] device_id, bit [ManufStateSize*8-1:0] manuf_state,
bit [EnSramIfetchSize*8-1:0] en_sram_ifetch,
bit [EnCsrngSwAppReadSize*8-1:0] en_csrng_sw_app_read,
bit [EnEntropySrcFwReadSize*8-1:0] en_entropy_src_fw_read,
bit [EnEntropySrcFwOverSize*8-1:0] en_entropy_src_fw_over);
bit [HwCfgDigestSize*8-1:0] digest;
bit [HwCfg0DigestSize*8-1:0] digest;

bit [bus_params_pkg::BUS_DW-1:0] hw_cfg_data[$];
bit [bus_params_pkg::BUS_DW-1:0] hw_cfg0_data[$];

for (int i = 0; i < DeviceIdSize; i += 4) begin
write32(i + DeviceIdOffset, device_id[i*8+:32]);
Expand All @@ -142,11 +142,11 @@ virtual function void otp_write_hw_cfg_partition(
write32(EnSramIfetchOffset,
{en_entropy_src_fw_over, en_entropy_src_fw_read, en_csrng_sw_app_read, en_sram_ifetch});

hw_cfg_data = {<<32 {32'h0, en_entropy_src_fw_over, en_entropy_src_fw_read,
en_csrng_sw_app_read, en_sram_ifetch, manuf_state, device_id}};
digest = cal_digest(HwCfgIdx, hw_cfg_data);
hw_cfg0_data = {<<32 {32'h0, en_entropy_src_fw_over, en_entropy_src_fw_read,
en_csrng_sw_app_read, en_sram_ifetch, manuf_state, device_id}};
digest = cal_digest(HwCfg0Idx, hw_cfg0_data);

write64(HwCfgDigestOffset, digest);
write64(HwCfg0DigestOffset, digest);
endfunction

// Functions that clear the provisioning state of the buffered partitions.
Expand All @@ -169,8 +169,8 @@ virtual function void otp_clear_secret2_partition();
end
endfunction

virtual function void otp_clear_hw_cfg_partition();
for (int i = 0; i < HwCfgSize; i += 4) begin
write32(i + HwCfgOffset, 32'h0);
virtual function void otp_clear_hw_cfg0_partition();
for (int i = 0; i < HwCfg0Size; i += 4) begin
write32(i + HwCfg0Offset, 32'h0);
end
endfunction
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ class flash_ctrl_hw_sec_otp_vseq extends flash_ctrl_base_vseq;
foreach (info_regions[i]) begin
// Get secret partition cfg from flash_ctrl_pkg
if ( i inside {1, 2}) begin
// Copy protection from hw_cfg.
// Copy protection from hw_cfg0.
info_regions[i] = conv2env_mp_info(flash_ctrl_pkg::CfgAllowRead);
// Update program and erase control for the test purpose.
info_regions[i].program_en = MuBi4True;
Expand Down
4 changes: 2 additions & 2 deletions hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_otf_base_vseq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ class flash_ctrl_otf_base_vseq extends flash_ctrl_base_vseq;
end
if (cfg.en_all_info_acc) allow_spec_info_acc = 3'h7;

// overwrite secret_partition cfg with hw_cfg
// overwrite secret_partition cfg with hw_cfg0
rand_info[0][0][1] = conv2env_mp_info(flash_ctrl_pkg::CfgAllowRead);
rand_info[0][0][2] = conv2env_mp_info(flash_ctrl_pkg::CfgAllowRead);
endfunction : post_randomize
Expand Down Expand Up @@ -1345,7 +1345,7 @@ class flash_ctrl_otf_base_vseq extends flash_ctrl_base_vseq;
if (scr_mode != OTFCfgRand) cfg.mp_info[i][j][k].scramble_en = scr_en;
if (ecc_mode != OTFCfgRand) cfg.mp_info[i][j][k].ecc_en = ecc_en;

// overwrite secret_partition cfg with hw_cfg
// overwrite secret_partition cfg with hw_cfg0
cfg.mp_info[0][0][1] = conv2env_mp_info(flash_ctrl_pkg::CfgAllowRead);
cfg.mp_info[0][0][2] = conv2env_mp_info(flash_ctrl_pkg::CfgAllowRead);

Expand Down
4 changes: 2 additions & 2 deletions hw/ip/lc_ctrl/data/lc_ctrl.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -1321,8 +1321,8 @@
{ multireg: {
name: "DEVICE_ID",
desc: '''
This is the 256bit DEVICE_ID value that is stored in the HW_CFG partition in OTP.
If this register reads all-one, the HW_CFG partition has not been initialized yet or is in error state.
This is the 256bit DEVICE_ID value that is stored in the HW_CFG0 partition in OTP.
If this register reads all-one, the HW_CFG0 partition has not been initialized yet or is in error state.
If this register reads all-zero, this is indicative that the value has not been programmed to OTP yet.
'''
count: "NumDeviceIdWords", // 8 x 32bit = 256bit
Expand Down
4 changes: 2 additions & 2 deletions hw/ip/lc_ctrl/doc/interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ Signal | Direction | Type
`otp_lc_data_i` | `input` | `otp_ctrl_pkg::otp_lc_data_t` | Life cycle state output holding the current life cycle state, the value of the transition counter and the tokens needed for life cycle transitions.
`lc_keymgr_div_o` | `output` | `lc_keymgr_div_t` | Life cycle state group diversification value.
`lc_flash_rma_seed_o` | `output` | `lc_flash_rma_seed_t` | Seed for flash RMA.
`otp_device_id_i` | `input` | `otp_device_id_t` | HW_CFG bits from OTP ([`DEVICE_ID_0`](registers.md#device_id)).
`otp_manuf_state_i` | `input` | `otp_manuf_state_t` | HW_CFG bits from OTP ([`MANUF_STATE_0`](registers.md#manuf_state)).
`otp_device_id_i` | `input` | `otp_device_id_t` | HW_CFG0 bits from OTP ([`DEVICE_ID_0`](registers.md#device_id)).
`otp_manuf_state_i` | `input` | `otp_manuf_state_t` | HW_CFG0 bits from OTP ([`MANUF_STATE_0`](registers.md#manuf_state)).
`lc_otp_vendor_test_o` | `output` | `otp_ctrl_pkg::lc_otp_vendor_test_req_t` | Vendor-specific test bits to OTP ([`OTP_VENDOR_TEST_CTRL`](registers.md#otp_vendor_test_ctrl)).
`lc_otp_vendor_test_i` | `input` | `otp_ctrl_pkg::lc_otp_vendor_test_rsp_t` | Vendor-specific test bits to OTP ([`OTP_VENDOR_TEST_STATUS`](registers.md#otp_vendor_test_status)).
`lc_dft_en_o` | `output` | `lc_tx_t` | [Multibit control signal](theory_of_operation.md#life-cycle-decoded-outputs-and-controls).
Expand Down
20 changes: 10 additions & 10 deletions hw/ip/lc_ctrl/doc/registers.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@
| lc_ctrl.[`LC_ID_STATE`](#lc_id_state) | 0x40 | 4 | This register exposes the id state of the device. |
| lc_ctrl.[`HW_REVISION0`](#hw_revision0) | 0x44 | 4 | This register holds the SILICON_CREATOR_ID and the PRODUCT_ID. |
| lc_ctrl.[`HW_REVISION1`](#hw_revision1) | 0x48 | 4 | This register holds the REVISION_ID. |
| lc_ctrl.[`DEVICE_ID_0`](#device_id) | 0x4c | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG partition in OTP. |
| lc_ctrl.[`DEVICE_ID_1`](#device_id) | 0x50 | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG partition in OTP. |
| lc_ctrl.[`DEVICE_ID_2`](#device_id) | 0x54 | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG partition in OTP. |
| lc_ctrl.[`DEVICE_ID_3`](#device_id) | 0x58 | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG partition in OTP. |
| lc_ctrl.[`DEVICE_ID_4`](#device_id) | 0x5c | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG partition in OTP. |
| lc_ctrl.[`DEVICE_ID_5`](#device_id) | 0x60 | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG partition in OTP. |
| lc_ctrl.[`DEVICE_ID_6`](#device_id) | 0x64 | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG partition in OTP. |
| lc_ctrl.[`DEVICE_ID_7`](#device_id) | 0x68 | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG partition in OTP. |
| lc_ctrl.[`DEVICE_ID_0`](#device_id) | 0x4c | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG0 partition in OTP. |
| lc_ctrl.[`DEVICE_ID_1`](#device_id) | 0x50 | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG0 partition in OTP. |
| lc_ctrl.[`DEVICE_ID_2`](#device_id) | 0x54 | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG0 partition in OTP. |
| lc_ctrl.[`DEVICE_ID_3`](#device_id) | 0x58 | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG0 partition in OTP. |
| lc_ctrl.[`DEVICE_ID_4`](#device_id) | 0x5c | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG0 partition in OTP. |
| lc_ctrl.[`DEVICE_ID_5`](#device_id) | 0x60 | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG0 partition in OTP. |
| lc_ctrl.[`DEVICE_ID_6`](#device_id) | 0x64 | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG0 partition in OTP. |
| lc_ctrl.[`DEVICE_ID_7`](#device_id) | 0x68 | 4 | This is the 256bit DEVICE_ID value that is stored in the HW_CFG0 partition in OTP. |
| lc_ctrl.[`MANUF_STATE_0`](#manuf_state) | 0x6c | 4 | This is a 256bit field used for keeping track of the manufacturing state. |
| lc_ctrl.[`MANUF_STATE_1`](#manuf_state) | 0x70 | 4 | This is a 256bit field used for keeping track of the manufacturing state. |
| lc_ctrl.[`MANUF_STATE_2`](#manuf_state) | 0x74 | 4 | This is a 256bit field used for keeping track of the manufacturing state. |
Expand Down Expand Up @@ -568,8 +568,8 @@ I.e., each base or metal layer respin must be reflected so that software can rel
Zero is an invalid value.

## DEVICE_ID
This is the 256bit DEVICE_ID value that is stored in the HW_CFG partition in OTP.
If this register reads all-one, the HW_CFG partition has not been initialized yet or is in error state.
This is the 256bit DEVICE_ID value that is stored in the HW_CFG0 partition in OTP.
If this register reads all-one, the HW_CFG0 partition has not been initialized yet or is in error state.
If this register reads all-zero, this is indicative that the value has not been programmed to OTP yet.
- Reset default: `0x0`
- Reset mask: `0xffffffff`
Expand Down
6 changes: 3 additions & 3 deletions hw/ip/otp_ctrl/data/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,10 @@ otp_json(
)

otp_json(
name = "otp_json_hw_cfg",
name = "otp_json_hw_cfg0",
partitions = [
otp_partition(
name = "HW_CFG",
name = "HW_CFG0",
items = {
"DEVICE_ID": "<random>",
# Enable code execution from SRAM in PROD state.
Expand Down Expand Up @@ -496,7 +496,7 @@ otp_image(
# after the test tokens have been applied and before running individualization.
# The following partitions are missing to ensure the image is initialized with
# values that would be present prior to the final individualization
# manufacturing stage: SECRET1, SECRET2, HW_CFG.
# manufacturing stage: SECRET1, SECRET2, HW_CFG0.
# The following partitions are expected to be configured in previous
# manufacturing stages: SECRET0, CREATOR_SW, OWNER_SW.
otp_image(
Expand Down
8 changes: 4 additions & 4 deletions hw/ip/otp_ctrl/data/earlgrey_a0_skus/prodc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,10 @@ otp_alert_digest(
)

otp_json(
name = "otp_json_hw_cfg",
name = "otp_json_hw_cfg0",
partitions = [
otp_partition(
name = "HW_CFG",
name = "HW_CFG0",
items = {
"DEVICE_ID": "<random>",
# Enable code execution from SRAM in PROD state.
Expand Down Expand Up @@ -292,10 +292,10 @@ MANUF_SW_INITIALIZED = [
":otp_json_owner_sw_cfg",
]

# The `MANUF_INDIVIDUALIZED` OTP profile configures the HW_CFG, CREATOR_SW and
# The `MANUF_INDIVIDUALIZED` OTP profile configures the HW_CFG0, CREATOR_SW and
# OWNER_SW OTP partitions. It also includes the `MANUF_INITIALIZED`.
MANUF_INDIVIDUALIZED = MANUF_INITIALIZED + MANUF_SW_INITIALIZED + [
":otp_json_hw_cfg",
":otp_json_hw_cfg0",
]

# The `MANUF_PERSONALIZED` OTP profile configures the SECRET1 and SECRET2 OTP
Expand Down
6 changes: 3 additions & 3 deletions hw/ip/otp_ctrl/data/earlgrey_a0_skus/sival/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,10 @@ otp_alert_digest(
)

otp_json(
name = "otp_json_hw_cfg",
name = "otp_json_hw_cfg0",
partitions = [
otp_partition(
name = "HW_CFG",
name = "HW_CFG0",
items = {
"DEVICE_ID": "<random>",
# Enable code execution from SRAM in PROD state.
Expand Down Expand Up @@ -295,7 +295,7 @@ MANUF_SW_INITIALIZED = [
# The `MANUF_INDIVIDUALIZED` OTP profile configures the HW_CFG, CREATOR_SW and
# OWNER_SW OTP partitions. It also includes the `MANUF_INITIALIZED`.
MANUF_INDIVIDUALIZED = MANUF_INITIALIZED + MANUF_SW_INITIALIZED + [
":otp_json_hw_cfg",
":otp_json_hw_cfg0",
]

# The `MANUF_PERSONALIZED` OTP profile configures the SECRET1 and SECRET2 OTP
Expand Down
6 changes: 3 additions & 3 deletions hw/ip/otp_ctrl/data/earlgrey_a0_skus/sival_bringup/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,10 @@ otp_alert_digest(
)

otp_json(
name = "otp_json_hw_cfg",
name = "otp_json_hw_cfg0",
partitions = [
otp_partition(
name = "HW_CFG",
name = "HW_CFG0",
items = {
"DEVICE_ID": "<random>",
# Enable code execution from SRAM in PROD state.
Expand Down Expand Up @@ -295,7 +295,7 @@ MANUF_SW_INITIALIZED = [
# The `MANUF_INDIVIDUALIZED` OTP profile configures the HW_CFG, CREATOR_SW and
# OWNER_SW OTP partitions. It also includes the `MANUF_INITIALIZED`.
MANUF_INDIVIDUALIZED = MANUF_INITIALIZED + MANUF_SW_INITIALIZED + [
":otp_json_hw_cfg",
":otp_json_hw_cfg0",
]

# The `MANUF_PERSONALIZED` OTP profile configures the SECRET1 and SECRET2 OTP
Expand Down
36 changes: 18 additions & 18 deletions hw/ip/otp_ctrl/data/otp_ctrl.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -872,14 +872,14 @@
default: "8",
local: "true"
},
{ name: "HwCfgOffset",
desc: "Offset of the HW_CFG partition",
{ name: "HwCfg0Offset",
desc: "Offset of the HW_CFG0 partition",
type: "int",
default: "1664",
local: "true"
},
{ name: "HwCfgSize",
desc: "Size of the HW_CFG partition",
{ name: "HwCfg0Size",
desc: "Size of the HW_CFG0 partition",
type: "int",
default: "80",
local: "true"
Expand Down Expand Up @@ -956,14 +956,14 @@
default: "1",
local: "true"
},
{ name: "HwCfgDigestOffset",
desc: "Offset of HW_CFG_DIGEST",
{ name: "HwCfg0DigestOffset",
desc: "Offset of HW_CFG0_DIGEST",
type: "int",
default: "1736",
local: "true"
},
{ name: "HwCfgDigestSize",
desc: "Size of HW_CFG_DIGEST",
{ name: "HwCfg0DigestSize",
desc: "Size of HW_CFG0_DIGEST",
type: "int",
default: "8",
local: "true"
Expand Down Expand Up @@ -1348,13 +1348,13 @@
desc: "Key derivation interface for OTBN scrambling devices."
}
// Hardware config partition
{ struct: "otp_hw_cfg"
{ struct: "otp_broadcast"
type: "uni"
name: "otp_hw_cfg"
name: "otp_broadcast"
act: "req"
default: "'0"
package: "otp_ctrl_part_pkg"
desc: "Output of the HW_CFG partition."
desc: "Output of the HW partitions with breakout data types."
}
// AST observability control
{ struct: "ast_obs_ctrl",
Expand Down Expand Up @@ -1543,13 +1543,13 @@
{
name: "OTP_CTRL.INIT"
desc: '''When power is up, OTP controller reads devices status.
After all reads complete, the controller performs integrity check on the HW_CFG and SECRET partitions.
After all reads complete, the controller performs integrity check on the HW_CFG* and SECRET partitions.
Once all integrity checks are complete, the controller marks outputs as valid.
'''
}
{
name: "OTP_CTRL.ENTROPY_READ"
desc: '''Firmware can read entropy from ENTROPY_SRC block by configuring following field of HW_CFG partition.
desc: '''Firmware can read entropy from ENTROPY_SRC block by configuring following field of HW_CFG* partition.
- EN_CSRNG_SW_APP_READ
- EN_ENTROPY_SRC_FW_READ
- EN_ENTROPY_SRC_FW_OVER
Expand Down Expand Up @@ -1665,7 +1665,7 @@
'''
}
{ bits: "3"
name: "HW_CFG_ERROR"
name: "HW_CFG0_ERROR"
desc: '''
Set to 1 if an error occurred in this partition.
If set to 1, SW should check the !!ERR_CODE register at the corresponding index.
Expand Down Expand Up @@ -2067,7 +2067,7 @@
{ name: "INTEGRITY_CHECK_PERIOD",
desc: '''
This value specifies the maximum period that can be generated pseudo-randomly.
Only applies to the HW_CFG and SECRET* partitions once they are locked.
Only applies to the HW_CFG* and SECRET* partitions once they are locked.
'''
swaccess: "rw",
hwaccess: "hro",
Expand All @@ -2089,7 +2089,7 @@
{ name: "CONSISTENCY_CHECK_PERIOD",
desc: '''
This value specifies the maximum period that can be generated pseudo-randomly.
This applies to the LIFE_CYCLE partition and the HW_CFG and SECRET* partitions once they are locked.
This applies to the LIFE_CYCLE partition and the HW_CFG* and SECRET* partitions once they are locked.
'''
swaccess: "rw",
hwaccess: "hro",
Expand Down Expand Up @@ -2249,9 +2249,9 @@
}
},
{ multireg: {
name: "HW_CFG_DIGEST",
name: "HW_CFG0_DIGEST",
desc: '''
Integrity digest for the HW_CFG partition.
Integrity digest for the HW_CFG0 partition.
The integrity digest is 0 by default. The digest calculation can be triggered via the !!DIRECT_ACCESS_CMD.
After a reset, the digest then becomes visible in this CSR, and the corresponding partition becomes write-locked.
''',
Expand Down
Loading

0 comments on commit a59ca1b

Please sign in to comment.