Hardware Interfaces

Parameters

The following table lists the instantiation parameters of OTP. Note that parameters prefixed with RndCnst are random netlist constants that need to be regenerated via topgen before the tapeout (typically by the silicon creator).

ParameterDefault (Max)Top EarlgreyDescription
AlertAsyncOn2’b112’b11
RndCnstLfsrSeed(see RTL)(see RTL)Seed to be used for the internal 40bit partition check timer LFSR. This needs to be replaced by the silicon creator before the tapeout.
RndCnstLfsrPerm(see RTL)(see RTL)Permutation to be used for the internal 40bit partition check timer LFSR. This needs to be replaced by the silicon creator before the tapeout.
RndCnstKey(see RTL)(see RTL)Random scrambling keys for secret partitions, to be used in the scrambling datapath.
RndCnstDigestConst(see RTL)(see RTL)Random digest finalization constants, to be used in the scrambling datapath.
RndCnstDigestIV(see RTL)(see RTL)Random digest initialization vectors, to be used in the scrambling datapath.
RndCnstRawUnlockToken(see RTL)(see RTL)Global RAW unlock token to be used for the first life cycle transition. See also conditional life cycle transitions.

Signals

Referring to the Comportable guideline for peripheral device functionality, the module otp_ctrl has the following hardware interfaces defined

  • Primary Clock: clk_i
  • Other Clocks: clk_edn_i
  • Bus Device Interfaces (TL-UL): core_tl, prim_tl
  • Bus Host Interfaces (TL-UL): none

Peripheral Pins for Chip IO

Pin nameDirectionDescription
test[7:0]outputTest-related GPIOs. Only active in DFT-enabled life cycle states.

Inter-Module Signals

Port NamePackage::StructTypeActWidthDescription
otp_ext_voltage_hionone1
otp_ast_pwr_seqotp_ctrl_pkg::otp_ast_requnireq1Power sequencing signals to AST (VDD domain).
otp_ast_pwr_seq_hotp_ctrl_pkg::otp_ast_rspunircv1Power sequencing signals coming from AST (VCC domain).
ednedn_pkg::ednreq_rspreq1Entropy request to the entropy distribution network for LFSR reseeding and ephemeral key derivation.
pwr_otppwrmgr_pkg::pwr_otpreq_rsprsp1Initialization request/acknowledge from/to power manager.
lc_otp_vendor_testotp_ctrl_pkg::lc_otp_vendor_testreq_rsprsp1Vendor test control signals from/to the life cycle TAP.
lc_otp_programotp_ctrl_pkg::lc_otp_programreq_rsprsp1Life cycle state transition interface.
otp_lc_dataotp_ctrl_pkg::otp_lc_dataunireq1Life cycle state output holding the current life cycle state, the value of the transition counter and the tokens needed for life cycle transitions.
lc_escalate_enlc_ctrl_pkg::lc_txunircv1Life cycle escalation enable coming from life cycle controller. This signal moves all FSMs within OTP into the error state.
lc_creator_seed_sw_rw_enlc_ctrl_pkg::lc_txunircv1Provision enable qualifier coming from life cycle controller. This signal enables SW read / write access to the RMA_TOKEN and CREATOR_ROOT_KEY_SHARE0 and CREATOR_ROOT_KEY_SHARE1.
lc_owner_seed_sw_rw_enlc_ctrl_pkg::lc_txunircv1Provision enable qualifier coming from life cycle controller. This signal enables SW read / write access to the OWNER_SEED.
lc_seed_hw_rd_enlc_ctrl_pkg::lc_txunircv1Seed read enable coming from life cycle controller. This signal enables HW read access to the CREATOR_ROOT_KEY_SHARE0 and CREATOR_ROOT_KEY_SHARE1.
lc_dft_enlc_ctrl_pkg::lc_txunircv1Test enable qualifier coming from life cycle controller. This signals enables the TL-UL access port to the proprietary OTP IP.
lc_check_byp_enlc_ctrl_pkg::lc_txunircv1Life cycle partition check bypass signal. This signal causes the life cycle partition to bypass consistency checks during life cycle state transitions in order to prevent spurious consistency check failures.
otp_keymgr_keyotp_ctrl_pkg::otp_keymgr_keyunireq1Key output to the key manager holding CREATOR_ROOT_KEY_SHARE0 and CREATOR_ROOT_KEY_SHARE1.
flash_otp_keyotp_ctrl_pkg::flash_otp_keyreq_rsprsp1Key derivation interface for FLASH scrambling.
sram_otp_keyotp_ctrl_pkg::sram_otp_keyreq_rsprsp4Array with key derivation interfaces for SRAM scrambling devices.
otbn_otp_keyotp_ctrl_pkg::otbn_otp_keyreq_rsprsp1Key derivation interface for OTBN scrambling devices.
otp_broadcastotp_ctrl_part_pkg::otp_broadcastunireq1Output of the HW partitions with breakout data types.
obs_ctrlast_pkg::ast_obs_ctrlunircv1AST observability control signals.
otp_obslogicunireq8AST observability bus.
core_tltlul_pkg::tlreq_rsprsp1
prim_tltlul_pkg::tlreq_rsprsp1

Interrupts

Interrupt NameTypeDescription
otp_operation_doneEventA direct access command or digest calculation operation has completed.
otp_errorEventAn error has occurred in the OTP controller. Check the ERR_CODE register to get more information.

Security Alerts

Alert NameDescription
fatal_macro_errorThis alert triggers if hardware detects an uncorrectable error during an OTP transaction, for example an uncorrectable ECC error in the OTP array.
fatal_check_errorThis alert triggers if any of the background checks fails. This includes the digest checks and concurrent ECC checks in the buffer registers.
fatal_bus_integ_errorThis fatal alert is triggered when a fatal TL-UL bus integrity fault is detected.
fatal_prim_otp_alertFatal alert triggered inside the OTP primitive, including fatal TL-UL bus integrity faults of the test interface.
recov_prim_otp_alertRecoverable alert triggered inside the OTP primitive.

Security Countermeasures

Countermeasure IDDescription
OTP_CTRL.BUS.INTEGRITYEnd-to-end bus integrity scheme.
OTP_CTRL.SECRET.MEM.SCRAMBLESecret partitions are scrambled with a full-round PRESENT cipher.
OTP_CTRL.PART.MEM.DIGESTIntegrity of buffered partitions is ensured via a 64bit digest.
OTP_CTRL.DAI.FSM.SPARSEThe direct access interface FSM is sparsely encoded.
OTP_CTRL.KDI.FSM.SPARSEThe key derivation interface FSM is sparsely encoded.
OTP_CTRL.LCI.FSM.SPARSEThe life cycle interface FSM is sparsely encoded.
OTP_CTRL.PART.FSM.SPARSEThe partition FSMs are sparsely encoded.
OTP_CTRL.SCRMBL.FSM.SPARSEThe scramble datapath FSM is sparsely encoded.
OTP_CTRL.TIMER.FSM.SPARSEThe background check timer FSM is sparsely encoded.
OTP_CTRL.DAI.CTR.REDUNThe direct access interface address counter employs a cross-counter implementation.
OTP_CTRL.KDI_SEED.CTR.REDUNThe key derivation interface counter employs a cross-counter implementation.
OTP_CTRL.KDI_ENTROPY.CTR.REDUNThe key derivation entropy counter employs a cross-counter implementation.
OTP_CTRL.LCI.CTR.REDUNThe life cycle interface address counter employs a cross-counter implementation.
OTP_CTRL.PART.CTR.REDUNThe address counter of buffered partitions employs a cross-counter implementation.
OTP_CTRL.SCRMBL.CTR.REDUNThe srambling datapath counter employs a cross-counter implementation.
OTP_CTRL.TIMER_INTEG.CTR.REDUNThe background integrity check timer employs a duplicated counter implementation.
OTP_CTRL.TIMER_CNSTY.CTR.REDUNThe background consistency check timer employs a duplicated counter implementation.
OTP_CTRL.TIMER.LFSR.REDUNThe background check LFSR is duplicated.
OTP_CTRL.DAI.FSM.LOCAL_ESCThe direct access interface FSM is moved into an invalid state upon local escalation.
OTP_CTRL.LCI.FSM.LOCAL_ESCThe life cycle interface FSM is moved into an invalid state upon local escalation.
OTP_CTRL.KDI.FSM.LOCAL_ESCThe key derivation interface FSM is moved into an invalid state upon local escalation.
OTP_CTRL.PART.FSM.LOCAL_ESCThe partition FSMs are moved into an invalid state upon local escalation.
OTP_CTRL.SCRMBL.FSM.LOCAL_ESCThe scramble datapath FSM is moved into an invalid state upon local escalation.
OTP_CTRL.TIMER.FSM.LOCAL_ESCThe background check timer FSM is moved into an invalid state upon local escalation.
OTP_CTRL.DAI.FSM.GLOBAL_ESCThe direct access interface FSM is moved into an invalid state upon global escalation via life cycle.
OTP_CTRL.LCI.FSM.GLOBAL_ESCThe life cycle interface FSM is moved into an invalid state upon global escalation via life cycle.
OTP_CTRL.KDI.FSM.GLOBAL_ESCThe key derivation interface FSM is moved into an invalid state upon global escalation via life cycle.
OTP_CTRL.PART.FSM.GLOBAL_ESCThe partition FSMs are moved into an invalid state upon global escalation via life cycle.
OTP_CTRL.SCRMBL.FSM.GLOBAL_ESCThe scramble datapath FSM is moved into an invalid state upon global escalation via life cycle.
OTP_CTRL.TIMER.FSM.GLOBAL_ESCThe background check timer FSM is moved into an invalid state upon global escalation via life cycle.
OTP_CTRL.PART.DATA_REG.INTEGRITYAll partition buffer registers are protected with ECC on 64bit blocks.
OTP_CTRL.PART.DATA_REG.BKGN_CHKThe digest of buffered partitions is recomputed and checked at pseudorandom intervals in the background.
OTP_CTRL.PART.MEM.REGRENUnbuffered (‘software’) partitions can be read-locked via a CSR until the next system reset.
OTP_CTRL.PART.MEM.SW_UNREADABLESecret buffered partitions become unreadable to software once they are locked via the digest.
OTP_CTRL.PART.MEM.SW_UNWRITABLEAll partitions become unwritable by software once they are locked via the digest.
OTP_CTRL.LC_PART.MEM.SW_NOACCESSThe life cycle partition is not directly readable nor writable via software.
OTP_CTRL.ACCESS.CTRL.MUBIThe access control signals going from the partitions to the DAI are MUBI encoded.
OTP_CTRL.TOKEN_VALID.CTRL.MUBIThe token valid signals going to the life cycle controller are MUBI encoded.
OTP_CTRL.LC_CTRL.INTERSIG.MUBIThe life cycle control signals are multibit encoded.
OTP_CTRL.TEST.BUS.LC_GATEDPrevent access to test signals and the OTP backdoor interface in non-test lifecycle states.
OTP_CTRL.TEST_TL_LC_GATE.FSM.SPARSEThe control FSM inside the TL-UL gating primitive is sparsely encoded.
OTP_CTRL.DIRECT_ACCESS.CONFIG.REGWENThe direct access CSRs are REGWEN protected.
OTP_CTRL.CHECK_TRIGGER.CONFIG.REGWENThe check trigger CSR is REGWEN protected.
OTP_CTRL.CHECK.CONFIG.REGWENThe check CSR is REGWEN protected.
OTP_CTRL.MACRO.MEM.INTEGRITYThe OTP macro employs a vendor-specific integrity scheme at the granularity of the native 16bit OTP words. The scheme is able to at least detect single bit errors.
OTP_CTRL.MACRO.MEM.CMThe OTP macro may contain additional vendor-specific countermeasures.

The OTP controller contains various interfaces that connect to other comportable IPs within OpenTitan, and these are briefly explained further below.

EDN Interface

The entropy request interface that talks to EDN in order to fetch fresh entropy for ephemeral SRAM scrambling key derivation and the LFSR counters for background checks. It is comprised of the otp_edn_o and otp_edn_i signals and follows a req / ack protocol.

See also EDN documentation.

Power Manager Interface

The power manager interface is comprised of three signals overall: an initialization request (pwr_otp_i.otp_init), an initialization done response (pwr_otp_o.otp_done) and an idle indicator (pwr_otp_o.otp_idle).

The power manager asserts pwr_otp_i.otp_init in order to signal to the OTP controller that it can start initialization, and the OTP controller signals completion of the initialization sequence by asserting pwr_otp_o.otp_done (the signal will remain high until reset).

The idle indication signal pwr_otp_o.otp_idle indicates whether there is an ongoing write operation in the Direct Access Interface (DAI) or Life Cycle Interface (LCI), and the power manager uses that indication to determine whether a power down request needs to be aborted.

Since the power manager may run in a different clock domain, the pwr_otp_i.otp_init signal is synchronized within the OTP controller. The power manager is responsible for synchronizing the pwr_otp_o.otp_done and pwr_otp_o.otp_idle signals.

See also power manager documentation.

Life Cycle Interfaces

The interface to the life cycle controller can be split into three functional sub-interfaces (vendor test, state output, state transitions), and these are explained in more detail below. Note that the OTP and life cycle controllers are supposed to be in the same clock domain, hence no additional signal synchronization is required. See also life cycle controller documentation for more details.

Vendor Test Signals

The lc_otp_vendor_test_i and lc_otp_vendor_test_o signals are connected to a 32bit control and a 32bit status register in the life cycle TAP, respectively, and are directly routed to the prim_otp wrapper. These control and status signals may be used by the silicon creator to exercise the OTP programming smoke checks on the VENDOR_TEST partition. The signals are gated with the life cycle state inside the life cycle controller such that they do not have any effect in production life cycle states.

State, Counter and Token Output

After initialization, the life cycle partition contents, as well as the tokens and personalization status is output to the life cycle controller via the otp_lc_data_o struct. The life cycle controller uses this information to determine the life cycle state, and steer the appropriate qualifier signals. Some of these qualifier signals (lc_dft_en_i, lc_creator_seed_sw_rw_en_i, lc_seed_hw_rd_en_i and lc_escalate_en_i) are fed back to the OTP controller in order to ungate testing logic to the OTP macro; enable SW write access to the SECRET2 partition; enable hardware read access to the root key in the SECRET2 partition; or to push the OTP controller into escalation state.

A possible sequence for the signals described is illustrated below.

{signal: [
  {name: 'clk_i',                           wave: 'p.................'},
  {name: 'otp_lc_data_o.valid',             wave: '0.|...|.1.|...|...'},
  {name: 'otp_lc_data_o.state',             wave: '03|...|...|...|...'},
  {name: 'otp_lc_data_o.count',             wave: '03|...|...|...|...'},
  {},
  {name: 'otp_lc_data_o.test_unlock_token', wave: '0.|...|.3.|...|...'},
  {name: 'otp_lc_data_o.test_exit_token',   wave: '0.|...|.3.|...|...'},
  {name: 'otp_lc_data_o.test_tokens_valid', wave: '0.|...|.3.|...|...'},
  {},
  {name: 'otp_lc_data_o.rma_token',         wave: '0.|.3.|...|...|...'},
  {name: 'otp_lc_data_o.rma_token_valid',   wave: '0.|.3.|...|...|...'},
  {},
  {name: 'otp_lc_data_o.secrets_valid',     wave: '0.|.3.|...|...|...'},
  {},
  {name: 'lc_creator_seed_sw_rw_en_i',      wave: '0.|...|...|.4.|...'},
  {name: 'lc_seed_hw_rd_en_i',              wave: '0.|...|...|.4.|...'},
  {name: 'lc_dft_en_i',                     wave: '0.|...|...|.4.|...'},
  {},
  {name: 'lc_escalate_en_i',                wave: '0.|...|...|...|.5.'},
]}

Note that the otp_lc_data_o.valid signal is only asserted after the LIFE_CYCLE, SECRET0 and SECRET2 partitions have successfully initialized, since the life cycle collateral contains information from all three partitions. The otp_lc_data_o.test_tokens_valid and otp_lc_data_o.rma_token_valid signals are multibit valid signals indicating whether the corresponding tokens are valid. The otp_lc_data_o.secrets_valid signal is a multibit valid signal that is set to lc_ctrl_pkg::On iff the SECRET2 partition containing the root keys has been locked with a digest.

State Transitions

In order to perform life cycle state transitions, the life cycle controller can present the new value of the life cycle state and counter via the programming interface as shown below:

{signal: [
  {name: 'clk_i',                          wave: 'p.......'},
  {name: 'lc_otp_program_i.req',           wave: '01.|..0.'},
  {name: 'lc_otp_program_i.state',         wave: '03.|..0.'},
  {name: 'lc_otp_program_i.count',         wave: '03.|..0.'},
  {name: 'lc_otp_program_o.ack',           wave: '0..|.10.'},
  {name: 'lc_otp_program_o.err',           wave: '0..|.40.'},
]}

The request must remain asserted until the life cycle controller has responded. An error is fatal and indicates that the OTP programming operation has failed.

Note that the new state must not clear any bits that have already been programmed to OTP - i.e., the new state must be incrementally programmable on top of the previous state. There are hence some implications on the life cycle encoding due to the ECC employed, see life cycle state encoding for details.

Note that the behavior of the lc_otp_program_i.otp_test_ctrl signal is vendor-specific, and hence the signal is set to x in the timing diagram above. The purpose of this signal is to control vendor-specific test mechanisms, and its value will only be forwarded to the OTP macro in RAW, TEST_* and RMA states. In all other life cycle states this signal will be clamped to zero.

Interface to Key Manager

The interface to the key manager is a simple struct that outputs the CREATOR_ROOT_KEY_SHARE0 and CREATOR_ROOT_KEY_SHARE1 keys via otp_keymgr_key_o if these secrets have been provisioned and locked (via CREATOR_KEY_LOCK). Otherwise, this signal is tied to a random netlist constant.

Since the key manager may run in a different clock domain, key manager is responsible for synchronizing the otp_keymgr_key_o signals.

Interface to Flash Scrambler

The interface to the FLASH scrambling device is a simple req/ack interface that provides the flash controller with the two 128bit keys for data and address scrambling.

The keys can be requested as illustrated below:

{signal: [
  {name: 'clk_i',                      wave: 'p...........'},
  {name: 'flash_otp_key_i.data_req',   wave: '01.|..0.|...'},
  {name: 'flash_otp_key_i.addr_req',   wave: '01.|....|..0'},
  {name: 'flash_otp_key_o.data_ack',   wave: '0..|.10.|...'},
  {name: 'flash_otp_key_o.addr_ack',   wave: '0..|....|.10'},
  {name: 'flash_otp_key_o.key',        wave: '0..|.30.|.40'},
  {name: 'flash_otp_key_o.seed_valid', wave: '0..|.10.|.10'},
]}

The keys are derived from the FLASH_DATA_KEY_SEED and FLASH_ADDR_KEY_SEED values stored in the SECRET1 partition using the scrambling primitive. If the key seeds have not yet been provisioned, the keys are derived from all-zero constants, and the flash_otp_key_o.seed_valid signal will be set to 0 in the response. The resulting scrambling key is still ephemeral (i.e., it is derived using entropy from CSRNG) and okay to be used.

Note that the req/ack protocol runs on the OTP clock. It is the task of the scrambling device to synchronize the handshake protocol by instantiating the prim_sync_reqack.sv primitive as shown below.

OTP Key Req Ack

Note that the key and nonce output signals on the OTP controller side are guaranteed to remain stable for at least 62 OTP clock cycles after the ack signal is pulsed high, because the derivation of a 64bit half-key takes at least two passes through the 31-cycle PRESENT primitive. Hence, if the scrambling device clock is faster or in the same order of magnitude as the OTP clock, the data can be directly sampled upon assertion of src_ack_o. If the scrambling device runs on a significantly slower clock than OTP, an additional register (as indicated with dashed grey lines in the figure) has to be added.

Interfaces to SRAM and OTBN Scramblers

The interfaces to the SRAM and OTBN scrambling devices follow a req / ack protocol, where the scrambling device first requests a new ephemeral key by asserting the request channel (sram_otp_key_i[*], otbn_otp_key_i). The OTP controller then fetches entropy from EDN and derives an ephemeral key using the SRAM_DATA_KEY_SEED and the PRESENT scrambling data path. Finally, the OTP controller returns a fresh ephemeral key via the response channels (sram_otp_key_o[*], otbn_otp_key_o), which complete the req / ack handshake. The wave diagram below illustrates this process for the OTBN scrambling device.

{signal: [
  {name: 'clk_i',                     wave: 'p.......'},
  {name: 'otbn_otp_key_i.req',        wave: '01.|..0.'},
  {name: 'otbn_otp_key_o.ack',        wave: '0..|.10.'},
  {name: 'otbn_otp_key_o.nonce',      wave: '0..|.30.'},
  {name: 'otbn_otp_key_o.key',        wave: '0..|.30.'},
  {name: 'otbn_otp_key_o.seed_valid', wave: '0..|.10.'},
]}

If the key seeds have not yet been provisioned, the keys are derived from all-zero constants, and the *.seed_valid signal will be set to 0 in the response. The resulting scrambling key is still ephemeral (i.e., it is derived using entropy from CSRNG) and okay to be used. It should be noted that this mechanism requires the EDN and entropy distribution network to be operational, and a key derivation request will block if they are not.

Note that the req/ack protocol runs on the OTP clock. It is the task of the scrambling device to perform the synchronization as described in the previous subsection on the flash scrambler interface.

Hardware Config Bits

The bits of the HW_CFG* partitions are output via the otp_ctrl_otp_broadcast_o struct. IPs that consume collateral stored in this partition shall connect to this struct via the topgen feature, and break out the appropriate bits by either accessing the correct index or using the struct fields. These fields are autogenerated from the memory map items allocated to the HW_CFG* partitions, and the autogenerated struct type can be found in the otp_ctrl_part_pkg.sv package. Note that it is the task of the receiving IP to synchronize these bits accordingly to the local clock. For convenience, a valid bit is also available in that struct. The valid bit indicates that the HW_CFG* partitions have initialized.

Parameter and Memory Map Changes after D3/V3

Note that all instantiation parameters can be changed without affecting D3/V3 status of the module. Similarly, it is permissible to change the contents (partition size, adding and removing items) of the CREATOR_SW_CFG, OWNER_SW_CFG and HW_CFG* partitions without affecting D3 status. Note however that partition size changes may affect V3 coverage metrics, hence if the size any of the above three partitions is changed, V3 needs to be re-assessed.