blob: 7acef8c0427ddfbb2214e2c16c0f9ac9fc29621b [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{ name: "otp_ctrl",
clock_primary: "clk_i",
bus_device: "tlul",
bus_host: "none",
///////////////////////////
// Interrupts and Alerts //
///////////////////////////
interrupt_list: [
{ name: "otp_operation_done",
desc: "A direct access command or digest calculation operation has completed."
}
{ name: "otp_error",
desc: "An error has occurred in the OTP controller. Check the ERR_CODE register to get more information."
}
],
alert_list: [
{ name: "otp_integrity_mismatch",
desc: "This alert triggers if hardware detects a parity bit or digest error in the buffered partitions.",
}
{ name: "otp_consistency_mismatch",
desc: "This alert triggers if the digest over the buffered registers does not match with the digest stored in OTP.",
}
],
////////////////
// Parameters //
////////////////
param_list: [
{ name: "OtpByteAddressWidth",
desc: "Width of the OTP Byte address.",
type: "int",
default: "11",
local: "true"
},
{ name: "NumCreatorSwCfgPartitionWords",
desc: "Number of 32bit words in the software config partitions.",
type: "int",
default: "192",
local: "true"
},
{ name: "NumOwnerSwCfgPartitionWords",
desc: "Number of 32bit words in the software config partitions.",
type: "int",
default: "192",
local: "true"
},
{ name: "NumHwCfgWords",
desc: "Number of 32bit words in the hardware config partition.",
type: "int",
default: "16",
local: "true"
},
{ name: "NumLcPartitionWords",
desc: "Number of 32bit words in the life cycle partition.",
type: "int",
default: "56",
local: "true"
},
{ name: "NumSecretPartitionWords",
desc: "Number of 32bit words in the secret partition.",
type: "int",
default: "56",
local: "true"
},
{ name: "NumDebugWindowWords",
desc: "Number of 32bit words in the debug window.",
type: "int",
default: "500",
local: "true"
},
]
/////////////////////////////
// Intermodule Connections //
/////////////////////////////
// TODO: these need to be refined during implementation and integration
inter_signal_list: [
// CSRNG interface
{ struct: "otp_csrng"
type: "req_rsp"
name: "otp_csrng"
act: "req"
package: "otp_ctrl_pkg"
}
// Power manager init command
{ struct: "pwr_otp"
type: "req_rsp"
name: "pwr_otp_init"
act: "rsp"
package: "pwrmgr_pkg"
}
// Status output to power manager
{ struct: "otp_pwr_state"
type: "uni"
name: "otp_pwr_state"
act: "req"
package: "otp_ctrl_pkg"
}
// LC transition command
{ struct: "lc_otp_program"
type: "req_rsp"
name: "lc_otp_program"
act: "rsp"
package: "otp_ctrl_pkg"
}
// Broadcast to LC
{ struct: "otp_lc_data"
type: "uni"
name: "otp_lc_data"
act: "req"
package: "otp_ctrl_pkg"
}
// Broadcast from LC
{ struct: "lc_tx"
type: "uni"
name: "lc_provision_en"
act: "rcv"
package: "lifecycle_pkg" // TODO: move to LC package?
}
{ struct: "lc_tx"
type: "uni"
name: "lc_test_en"
act: "rcv"
package: "lifecycle_pkg" // TODO: move to LC package?
}
// Broadcast to Key Manager
{ struct: "keymgr_key"
type: "uni"
name: "otp_keymgr_key"
act: "req"
package: "otp_ctrl_pkg" // TODO: move this to keymgr package?
}
// Broadcast to Flash Controller
{ struct: "flash_key"
type: "uni"
name: "otp_flash_key"
act: "req"
package: "otp_ctrl_pkg"
}
// Key request from Main RAM Scrambler
{ struct: "ram_main_key"
type: "req_rsp"
name: "otp_ram_main_key"
act: "rsp"
package: "otp_ctrl_pkg"
}
// Key request from Retention RAM Scrambler
{ struct: "ram_ret_aon_key"
type: "req_rsp"
name: "otp_ram_ret_aon_key"
act: "rsp"
package: "otp_ctrl_pkg"
}
// Key request from OTBN RAM Scrambler
{ struct: "otbn_ram_key"
type: "req_rsp"
name: "otp_otbn_ram_key"
act: "rsp"
package: "otp_ctrl_pkg"
}
] // inter_signal_list
regwidth: "32",
registers: [
////////////////////////
// Ctrl / Status CSRs //
////////////////////////
// TODO: this may have to be refined during implementation.
{ name: "STATUS",
desc: "OTP status register.",
swaccess: "ro",
hwaccess: "hwo",
fields: [
{ bits: "2:0"
enum: [
{ value: "0",
name: "IDLE",
desc: '''
OTP is in IDLE state and ready to accept commands.
'''
},
{ value: "1",
name: "INIT",
desc: '''
OTP is initializing.
'''
},
{ value: "2",
name: "ERROR",
desc: '''
An error condition has occurred.
Please check the ERR_CODE register for specifics.
'''
},
{ value: "3",
name: "READ_PENDING",
desc: '''
A read operation is pending.
'''
},
{ value: "4",
name: "WRITE_PENDING",
desc: '''
A write operation is pending.
'''
},
]
}
]
}
// TODO: need to define error codes for errors during background operations (or add alerts for them)
{ name: "ERR_CODE",
desc: '''This register holds information on error conditions and should be
checked when !!STATUS indicates that an error has occurred, or when
an !!INTR_STATE.otp_error has been triggered.
'''
swaccess: "ro",
hwaccess: "hwo",
fields: [
{
bits: "2:0"
enum: [
{ value: "0",
name: "NONE",
desc: '''
No error condition has occurred.
'''
},
{ value: "1",
name: "MISSING_INIT",
desc: '''
Read or write operation attempted before initialization.
The OTP controller automatically recovers from this error when initializing.
'''
},
{ value: "2",
name: "INVALID_CMD",
desc: '''
Invalid command has been written to !!DIRECT_ACCESS_CMD.
The OTP controller automatically recovers from this error when issuing a new command.
'''
},
{ value: "3",
name: "READ_CORR",
desc: '''
A correctable error has occured during a read operation.
The OTP controller automatically recovers from this error when issuing a new command.
'''
},
{ value: "4",
name: "READ_UNCORR",
desc: '''
An uncorrectable error has occurred during a read operation.
The OTP controller automatically recovers from this error when issuing a new command.
'''
},
{ value: "5",
name: "READ_ERR",
desc: '''
An error has occurred during a read operation.
The OTP controller may not be able to automatically recover from this error and has to be reset.
'''
},
{ value: "6",
name: "WRITE_ERR",
desc: '''
An error has occurred during a programming operation.
The OTP controller may not be able to automatically recover from this error and has to be reset.
'''
},
{ value: "7",
name: "ESCALATED",
desc: '''
OTP has been rendered unusable due to an escalation.
This is a terminal state.
'''
},
]
}
]
}
{ name: "DIRECT_ACCESS_CMD",
desc: "Command register for direct accesses.",
swaccess: "r0w1c",
hwaccess: "hro",
hwext: "true",
hwqe: "true",
fields: [
{ bits: "0",
name: "read",
desc: '''
Initiates a readout sequence that reads the location specified
by !!DIRECT_ACCESS_ADDRESS. The command places the data read into
!!DIRECT_ACCESS_RDATA_0 and !!DIRECT_ACCESS_RDATA_1 (for 64bit partitions).
'''
}
{ bits: "1",
name: "write",
desc: '''
Initiates a programming sequence that writes the data in !!DIRECT_ACCESS_WDATA_0
and !!DIRECT_ACCESS_WDATA_1 (for 64bit partitions) to the location specified by
!!DIRECT_ACCESS_ADDRESS.
'''
}
]
}
{ name: "DIRECT_ACCESS_ADDRESS",
desc: "Address register for direct accesses.",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "OtpByteAddressWidth-1:0",
desc: '''
This is the address for the OTP word to be read or written through
the direct access interface. Note that the address is aligned to the access size
internally, hence bits 1:0 are ignored for 32bit accesses, and bits 2:0 are ignored
for 64bit accesses.
'''
}
]
}
{ multireg: {
name: "DIRECT_ACCESS_WDATA",
desc: '''Write data for direct accesses.
Hardware automatically determines the access granule (32bit or 64bit) based on which
partition is being written to.
''',
count: "2", // 2 x 32bit = 64bit
swaccess: "rw",
hwaccess: "hro",
hwqe: "true",
cname: "WORD",
fields: [
{ bits: "31:0"
}
]
}
},
{ multireg: {
name: "DIRECT_ACCESS_RDATA",
desc: '''Read data for direct accesses.
Hardware automatically determines the access granule (32bit or 64bit) based on which
partition is read from.
''',
count: "2", // 2 x 32bit = 64bit
swaccess: "ro",
hwaccess: "hwo",
cname: "WORD",
fields: [
{ bits: "31:0"
}
]
}
},
{ name: "CHECK_PERIOD_REGEN",
desc: '''
Register write enable for !!INTEGRITY_CHECK_PERIOD_MSB and !!CONSISTENCY_CHECK_PERIOD_MSB.
''',
swaccess: "rw1c",
hwaccess: "hro",
fields: [
{ bits: "0",
desc: '''
When true, !!INTEGRITY_CHECK_PERIOD_MSB and !!CONSISTENCY_CHECK_PERIOD_MSB registers cannot be written anymore.
'''
resval: 1,
},
]
},
{ name: "INTEGRITY_CHECK_PERIOD_MSB",
desc: '''
This value specifies the maximum period that can be generated pseudo-randomly.
Only applies to the HW_CFG and SECRET partitions if they are locked.
'''
swaccess: "rw",
hwaccess: "hro",
regwen: "CHECK_PERIOD_REGEN",
fields: [
{ bits: "5:0",
desc: '''
The pseudo-random period is generated using a 40bit LFSR internally, and this value defines
the bit mask to be applied to the LFSR output in order to limit its range. A value of N will generate
an internal mask of 2^N-1. So for N=16 this would allow the maximum pseudo-random period to be 0xFFFF cycles.
The default value has been set to 27, which corresponds to a maximum period of a bit more than 1.3s at 100MHz.
'''
resval: "27"
}
]
}
{ name: "CONSISTENCY_CHECK_PERIOD_MSB",
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 (but only if they are locked).
'''
swaccess: "rw",
hwaccess: "hro",
regwen: "CHECK_PERIOD_REGEN",
fields: [
{ bits: "5:0",
desc: '''
The pseudo-random period is generated using a 40bit LFSR internally, and this value defines
the bit mask to be applied to the LFSR output in order to limit its range. A value of N will generate
an internal mask of 2^N-1. So for N=16 this would allow the maximum pseudo-random period to be 0xFFFF cycles.
The default value has been set to 30, which corresponds to a maximum period of a bit more than 10s at 100MHz.
'''
resval: "30"
}
]
}
////////////////////////////////////
// Dynamic Locks of SW Parititons //
////////////////////////////////////
{ name: "CREATOR_SW_CFG_READ_LOCK",
desc: '''
Runtime read lock for the creator software partition.
''',
swaccess: "rw1c",
hwaccess: "hro",
fields: [
{ bits: "0",
desc: '''
When true, read access to the !!CREATOR_SW_CFG partition is locked.
'''
resval: 1,
},
]
},
{ name: "OWNER_SW_CFG_READ_LOCK",
desc: '''
Runtime read lock for the owner software partition.
''',
swaccess: "rw1c",
hwaccess: "hro",
fields: [
{ bits: "0",
desc: '''
When true, read access to the !!OWNER_SW_CFG partition is locked.
'''
resval: 1,
},
]
},
///////////////////////
// Integrity Digests //
///////////////////////
{ name: "HW_CFG_DIGEST_CALC",
desc: "Compute and program digest for the HW_CFG partition.",
swaccess: "r0w1c",
hwaccess: "hro",
fields: [
{ bits: "0",
desc: '''
Writing 1 to this register computes the partition digest and burns it into OTP.
After a reset, write access to the HW_CFG partition is locked, and the digest
becomes visible in !!HW_CFG_DIGEST.
'''
}
]
}
{ name: "SECRET_DIGEST_CALC",
desc: "Compute and program digest for the secret partition.",
swaccess: "r0w1c",
hwaccess: "hro",
fields: [
{ bits: "0",
desc: '''
Writing 1 to this register computes the partition digest and burns it into OTP.
After a reset, write and read access to the SECRET partition is locked, and the digest
becomes visible in !!SECRET_DIGEST.
'''
}
]
}
{ name: "CREATOR_SW_CFG_DIGEST",
desc: "Integrity digest for the creator software config partition.",
swaccess: "ro",
hwaccess: "hwo",
hwext: "true",
fields: [
{ bits: "31:0",
desc: '''
The integrity digest is 0 by default. Software must write this
digest value via the direct access interface in order to lock the partition.
After a reset, write access to the !!CREATOR_SW_CFG partition is locked and
the digest becomes visible in this CSR.
'''
}
]
}
{ name: "OWNER_SW_CFG_DIGEST",
desc: "Integrity digest for the owner software config partition.",
swaccess: "ro",
hwaccess: "hwo",
hwext: "true",
fields: [
{ bits: "31:0",
desc: '''
The integrity digest is 0 by default. Software must write this
digest value via the direct access interface in order to lock the partition.
After a reset, write access to the !!OWNER_SW_CFG partition is locked and
the digest becomes visible in this CSR.
'''
}
]
}
{ name: "HW_CFG_DIGEST",
desc: "Hardware config partition integrity digest.",
swaccess: "ro",
hwaccess: "hwo",
hwext: "true",
fields: [
{ bits: "31:0",
desc: '''
The integrity digest is 0 by default. Once the HW_CFG partition has been locked by
writing to !!HW_CFG_DIGEST_CALC, the digest becomes visible in this CSR after a reset.
'''
}
]
}
{ name: "SECRET_DIGEST",
desc: "Integrity digest for the secret config partition.",
swaccess: "ro",
hwaccess: "hwo",
hwext: "true",
fields: [
{ bits: "31:0",
desc: '''
The integrity digest is 0 by default. Once the SECRET partition has been locked by
writing to !!SECRET_DIGEST_CALC, the digest becomes visible in this CSR after a reset.
'''
}
]
}
///////////////////////////////
// Hardware Config Partition //
///////////////////////////////
{ skipto: "0x100" }
{ name: "TEST_TOKENS_LOCK",
desc: '''
TEST token lock value. When set to nonzero, the life cycle tokens TEST_UNLOCK_TOKEN
and TEST_EXIT_TOKEN are no longer accessible to software.
'''
swaccess: "ro",
hwaccess: "hwo",
hwext: "true",
fields: [
{ bits: "31:0"
}
]
}
{ name: "RMA_TOKEN_LOCK",
desc: '''
RMA token lock value. When set to nonzero, the life cycle
RMA_TOKEN is no longer accessible to software.
'''
swaccess: "ro",
hwaccess: "hwo",
hwext: "true",
fields: [
{ bits: "31:0",
}
]
}
{ name: "FLASH_KEYS_LOCK",
desc: '''
FLASH key lock value. When set to nonzero, the
FLASH_ADDR_KEY and FLASH_DATA_KEY are no longer accessible to software.
'''
swaccess: "ro",
hwaccess: "hwo",
hwext: "true",
fields: [
{ bits: "31:0",
}
]
}
{ name: "SRAM_KEY_LOCK",
desc: '''
SRAM key lock value. When set to nonzero, the
SRAM_KEY_LOCK is no longer accessible to software.
'''
swaccess: "ro",
hwaccess: "hwo",
hwext: "true",
fields: [
{ bits: "31:0",
}
]
}
{ name: "CREATOR_KEY_LOCK",
desc: '''
CREATOR key lock value. When set to nonzero, the
CREATOR_ROOT_KEY_SHARE0 and CREATOR_ROOT_KEY_SHARE1 are no longer accessible to software.
'''
swaccess: "ro",
hwaccess: "hwo",
hwext: "true",
fields: [
{ bits: "31:0",
}
]
}
// TODO: there is likely more collateral that needs to be stored in the HW_CFG partition.
// add them as they become apparent.
//////////////////////////
// Life Cycle Partition //
//////////////////////////
{ skipto: "0x200" }
{ multireg: {
name: "LC_STATE",
desc: '''
Life cycle state, comprised of 9 Byte groups.
TODO: add link to LC controller spec.
''',
count: "9",
swaccess: "ro",
hwaccess: "hwo",
cname: "BYTE",
fields: [
{ bits: "7:0"
enum: [
{ value: "0",
name: "BLANK",
desc: '''
0x00
'''
},
{ value: "106",
name: "ONE",
desc: '''
0x6A
'''
},
{ value: "149",
name: "TWO",
desc: '''
0x95
'''
},
{ value: "255",
name: "FULL",
desc: '''
0xFF
'''
},
]
}
]
}
},
{ name: "TRANSITION_CNT",
desc: "Counter for total amount of state transition attempts.",
swaccess: "ro",
hwaccess: "hwo",
fields: [
{ bits: "31:0",
desc: '''
This counter will be incremented upon each state transition attempt,
or when the transition command coming from the life cycle controller is invalid.
'''
}
]
}
///////////////////////////////
// Software Config Partition //
///////////////////////////////
{ skipto: "0x300" }
{ window: {
name: "CREATOR_SW_CFG"
items: "NumCreatorSwCfgPartitionWords"
swaccess: "ro",
desc: '''
Any read to this window directly maps to the corresponding offset in the creator software
config partition, and triggers an OTP readout of the Bytes requested. Note that the transaction
will block until OTP readout has completed.
'''
}
}
{ skipto: "0x700" }
{ window: {
name: "OWNER_SW_CFG"
items: "NumOwnerSwCfgPartitionWords"
swaccess: "ro",
desc: '''
Any read to this window directly maps to the corresponding offset in the owner software
config partition, and triggers an OTP readout of the Bytes requested. Note that the transaction
will block until OTP readout has completed.
'''
}
}
//////////////////////
// Test Access Port //
//////////////////////
{ skipto: "0xB00" }
// TODO: may have to update description, once it is known how RAW unlock is handled.
{ window: {
name: "TEST_ACCESS"
items: "NumDebugWindowWords"
swaccess: "rw",
desc: '''
This maps to the register file of the proprietary OTP macro. Note that this is only
accessible during the TEST life cycle state.
'''
}
}
],
}