diff --git a/SUMMARY.md b/SUMMARY.md index fe86109fd0c1a..2aa4eb0b9a39b 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -194,7 +194,8 @@ - [Design Verification](./hw/ip/otp_ctrl/dv/README.md) - [Testplan](./hw/ip/otp_ctrl/data/otp_ctrl_testplan.hjson) - [Programmer's Guide](./hw/ip/otp_ctrl/doc/programmers_guide.md) - - [Interface and Registers](./hw/ip/otp_ctrl/data/otp_ctrl.hjson) + - [Hardware Interfaces](./hw/ip/otp_ctrl/doc/interfaces.md) + - [Registers](./hw/ip/otp_ctrl/doc/registers.md) - [Device Interface Functions](./sw/device/lib/dif/dif_otp_ctrl.h) - [Checklist](./hw/ip/otp_ctrl/doc/checklist.md) - [Pattern Generator](./hw/ip/pattgen/README.md) diff --git a/hw/ip/otp_ctrl/doc/interfaces.md b/hw/ip/otp_ctrl/doc/interfaces.md new file mode 100644 index 0000000000000..15562f4c33c50 --- /dev/null +++ b/hw/ip/otp_ctrl/doc/interfaces.md @@ -0,0 +1,300 @@ +# 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). + +Parameter | Default (Max) | Top Earlgrey | Description +----------------------------|---------------|--------------|--------------- +`AlertAsyncOn` | 2'b11 | 2'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](#scrambling-datapath). +`RndCnstDigestConst` | (see RTL) | (see RTL) | Random digest finalization constants, to be used in the [scrambling datapath](#scrambling-datapath). +`RndCnstDigestIV` | (see RTL) | (see RTL) | Random digest initialization vectors, to be used in the [scrambling datapath](#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](../../lc_ctrl/README.md#conditional-transitions). + +## Signals + + +Referring to the [Comportable guideline for peripheral device functionality](https://opentitan.org/book/doc/contributing/hw/comportability), 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 name | Direction | Description | +|:-----------|:------------|:------------------------------------------------------------------| +| test[7:0] | output | Test-related GPIOs. Only active in DFT-enabled life cycle states. | + +## [Inter-Module Signals](https://opentitan.org/book/doc/contributing/hw/comportability/index.html#inter-signal-handling) + +| Port Name | Package::Struct | Type | Act | Width | Description | +|:-------------------------|:---------------------------------|:--------|:------|--------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| otp_ext_voltage_h | | io | none | 1 | | +| otp_ast_pwr_seq | otp_ctrl_pkg::otp_ast_req | uni | req | 1 | Power sequencing signals to AST (VDD domain). | +| otp_ast_pwr_seq_h | otp_ctrl_pkg::otp_ast_rsp | uni | rcv | 1 | Power sequencing signals coming from AST (VCC domain). | +| edn | edn_pkg::edn | req_rsp | req | 1 | Entropy request to the entropy distribution network for LFSR reseeding and ephemeral key derivation. | +| pwr_otp | pwrmgr_pkg::pwr_otp | req_rsp | rsp | 1 | Initialization request/acknowledge from/to power manager. | +| lc_otp_vendor_test | otp_ctrl_pkg::lc_otp_vendor_test | req_rsp | rsp | 1 | Vendor test control signals from/to the life cycle TAP. | +| lc_otp_program | otp_ctrl_pkg::lc_otp_program | req_rsp | rsp | 1 | Life cycle state transition interface. | +| otp_lc_data | otp_ctrl_pkg::otp_lc_data | uni | req | 1 | 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_escalate_en | lc_ctrl_pkg::lc_tx | uni | rcv | 1 | Life cycle escalation enable coming from life cycle controller. This signal moves all FSMs within OTP into the error state. | +| lc_creator_seed_sw_rw_en | lc_ctrl_pkg::lc_tx | uni | rcv | 1 | Provision 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_seed_hw_rd_en | lc_ctrl_pkg::lc_tx | uni | rcv | 1 | Seed 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_en | lc_ctrl_pkg::lc_tx | uni | rcv | 1 | Test enable qualifier coming from life cycle controller. This signals enables the TL-UL access port to the proprietary OTP IP. | +| lc_check_byp_en | lc_ctrl_pkg::lc_tx | uni | rcv | 1 | Life 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_key | otp_ctrl_pkg::otp_keymgr_key | uni | req | 1 | Key output to the key manager holding CREATOR_ROOT_KEY_SHARE0 and CREATOR_ROOT_KEY_SHARE1. | +| flash_otp_key | otp_ctrl_pkg::flash_otp_key | req_rsp | rsp | 1 | Key derivation interface for FLASH scrambling. | +| sram_otp_key | otp_ctrl_pkg::sram_otp_key | req_rsp | rsp | 3 | Array with key derivation interfaces for SRAM scrambling devices. | +| otbn_otp_key | otp_ctrl_pkg::otbn_otp_key | req_rsp | rsp | 1 | Key derivation interface for OTBN scrambling devices. | +| otp_hw_cfg | otp_ctrl_part_pkg::otp_hw_cfg | uni | req | 1 | Output of the HW_CFG partition. | +| obs_ctrl | ast_pkg::ast_obs_ctrl | uni | rcv | 1 | AST observability control signals. | +| otp_obs | logic | uni | req | 8 | AST observability bus. | +| core_tl | tlul_pkg::tl | req_rsp | rsp | 1 | | +| prim_tl | tlul_pkg::tl | req_rsp | rsp | 1 | | + +## Interrupts + +| Interrupt Name | Type | Description | +|:-------------------|:-------|:-----------------------------------------------------------------------------------------------------------------------------| +| otp_operation_done | Event | A direct access command or digest calculation operation has completed. | +| otp_error | Event | An error has occurred in the OTP controller. Check the [`ERR_CODE`](registers.md#err_code) register to get more information. | + +## Security Alerts + +| Alert Name | Description | +|:----------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------| +| fatal_macro_error | This alert triggers if hardware detects an uncorrectable error during an OTP transaction, for example an uncorrectable ECC error in the OTP array. | +| fatal_check_error | This 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_error | This fatal alert is triggered when a fatal TL-UL bus integrity fault is detected. | +| fatal_prim_otp_alert | Fatal alert triggered inside the OTP primitive, including fatal TL-UL bus integrity faults of the test interface. | +| recov_prim_otp_alert | Recoverable alert triggered inside the OTP primitive. | + +## Security Countermeasures + +| Countermeasure ID | Description | +|:-------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| OTP_CTRL.BUS.INTEGRITY | End-to-end bus integrity scheme. | +| OTP_CTRL.SECRET.MEM.SCRAMBLE | Secret partitions are scrambled with a full-round PRESENT cipher. | +| OTP_CTRL.PART.MEM.DIGEST | Integrity of buffered partitions is ensured via a 64bit digest. | +| OTP_CTRL.DAI.FSM.SPARSE | The direct access interface FSM is sparsely encoded. | +| OTP_CTRL.KDI.FSM.SPARSE | The key derivation interface FSM is sparsely encoded. | +| OTP_CTRL.LCI.FSM.SPARSE | The life cycle interface FSM is sparsely encoded. | +| OTP_CTRL.PART.FSM.SPARSE | The partition FSMs are sparsely encoded. | +| OTP_CTRL.SCRMBL.FSM.SPARSE | The scramble datapath FSM is sparsely encoded. | +| OTP_CTRL.TIMER.FSM.SPARSE | The background check timer FSM is sparsely encoded. | +| OTP_CTRL.DAI.CTR.REDUN | The direct access interface address counter employs a cross-counter implementation. | +| OTP_CTRL.KDI_SEED.CTR.REDUN | The key derivation interface counter employs a cross-counter implementation. | +| OTP_CTRL.KDI_ENTROPY.CTR.REDUN | The key derivation entropy counter employs a cross-counter implementation. | +| OTP_CTRL.LCI.CTR.REDUN | The life cycle interface address counter employs a cross-counter implementation. | +| OTP_CTRL.PART.CTR.REDUN | The address counter of buffered partitions employs a cross-counter implementation. | +| OTP_CTRL.SCRMBL.CTR.REDUN | The srambling datapath counter employs a cross-counter implementation. | +| OTP_CTRL.TIMER_INTEG.CTR.REDUN | The background integrity check timer employs a duplicated counter implementation. | +| OTP_CTRL.TIMER_CNSTY.CTR.REDUN | The background consistency check timer employs a duplicated counter implementation. | +| OTP_CTRL.TIMER.LFSR.REDUN | The background check LFSR is duplicated. | +| OTP_CTRL.DAI.FSM.LOCAL_ESC | The direct access interface FSM is moved into an invalid state upon local escalation. | +| OTP_CTRL.LCI.FSM.LOCAL_ESC | The life cycle interface FSM is moved into an invalid state upon local escalation. | +| OTP_CTRL.KDI.FSM.LOCAL_ESC | The key derivation interface FSM is moved into an invalid state upon local escalation. | +| OTP_CTRL.PART.FSM.LOCAL_ESC | The partition FSMs are moved into an invalid state upon local escalation. | +| OTP_CTRL.SCRMBL.FSM.LOCAL_ESC | The scramble datapath FSM is moved into an invalid state upon local escalation. | +| OTP_CTRL.TIMER.FSM.LOCAL_ESC | The background check timer FSM is moved into an invalid state upon local escalation. | +| OTP_CTRL.DAI.FSM.GLOBAL_ESC | The direct access interface FSM is moved into an invalid state upon global escalation via life cycle. | +| OTP_CTRL.LCI.FSM.GLOBAL_ESC | The life cycle interface FSM is moved into an invalid state upon global escalation via life cycle. | +| OTP_CTRL.KDI.FSM.GLOBAL_ESC | The key derivation interface FSM is moved into an invalid state upon global escalation via life cycle. | +| OTP_CTRL.PART.FSM.GLOBAL_ESC | The partition FSMs are moved into an invalid state upon global escalation via life cycle. | +| OTP_CTRL.SCRMBL.FSM.GLOBAL_ESC | The scramble datapath FSM is moved into an invalid state upon global escalation via life cycle. | +| OTP_CTRL.TIMER.FSM.GLOBAL_ESC | The background check timer FSM is moved into an invalid state upon global escalation via life cycle. | +| OTP_CTRL.PART.DATA_REG.INTEGRITY | All partition buffer registers are protected with ECC on 64bit blocks. | +| OTP_CTRL.PART.DATA_REG.BKGN_CHK | The digest of buffered partitions is recomputed and checked at pseudorandom intervals in the background. | +| OTP_CTRL.PART.MEM.REGREN | Unbuffered ('software') partitions can be read-locked via a CSR until the next system reset. | +| OTP_CTRL.PART.MEM.SW_UNREADABLE | Secret buffered partitions become unreadable to software once they are locked via the digest. | +| OTP_CTRL.PART.MEM.SW_UNWRITABLE | All partitions become unwritable by software once they are locked via the digest. | +| OTP_CTRL.LC_PART.MEM.SW_NOACCESS | The life cycle partition is not directly readable nor writable via software. | +| OTP_CTRL.ACCESS.CTRL.MUBI | The access control signals going from the partitions to the DAI are MUBI encoded. | +| OTP_CTRL.TOKEN_VALID.CTRL.MUBI | The token valid signals going to the life cycle controller are MUBI encoded. | +| OTP_CTRL.LC_CTRL.INTERSIG.MUBI | The life cycle control signals are multibit encoded. | +| OTP_CTRL.TEST.BUS.LC_GATED | Prevent access to test signals and the OTP backdoor interface in non-test lifecycle states. | +| OTP_CTRL.TEST_TL_LC_GATE.FSM.SPARSE | The control FSM inside the TL-UL gating primitive is sparsely encoded. | +| OTP_CTRL.DIRECT_ACCESS.CONFIG.REGWEN | The direct access CSRs are REGWEN protected. | +| OTP_CTRL.CHECK_TRIGGER.CONFIG.REGWEN | The check trigger CSR is REGWEN protected. | +| OTP_CTRL.CHECK.CONFIG.REGWEN | The check CSR is REGWEN protected. | +| OTP_CTRL.MACRO.MEM.INTEGRITY | The 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.CM | The 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](../../edn/README.md). + +### 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](../../pwrmgr/README.md). + +### 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](../../lc_ctrl/README.md) 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. +```wavejson +{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: + +```wavejson +{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](../../lc_ctrl/README.md#life-cycle-manufacturing-state-encodings) 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: + +```wavejson +{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](#scrambling-datapath). +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. + +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](../doc/otp_ctrl_key_req_ack.svg) + +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](#scrambling-datapath). +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. + +```wavejson +{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. +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](#interface-to-flash-scrambler). + +### Hardware Config Bits + +The bits of the HW_CFG partition are output via the `otp_hw_cfg_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 partition, 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 partition has 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. diff --git a/hw/ip/otp_ctrl/doc/programmers_guide.md b/hw/ip/otp_ctrl/doc/programmers_guide.md index eb5419fd04c46..1456ae35dcb39 100644 --- a/hw/ip/otp_ctrl/doc/programmers_guide.md +++ b/hw/ip/otp_ctrl/doc/programmers_guide.md @@ -13,16 +13,16 @@ Typical programming sequences are explained at the end of the Programmer's guide The OTP controller initializes automatically upon power-up and is fully operational by the time the processor boots. The only initialization steps that SW should perform are: -1. Check that the OTP controller has successfully initialized by reading [`STATUS`](../data/otp_ctrl.hjson#status). I.e., make sure that none of the ERROR bits are set, and that the DAI is idle ([`STATUS.DAI_IDLE`](../data/otp_ctrl.hjson#status)). +1. Check that the OTP controller has successfully initialized by reading [`STATUS`](registers.md#status). I.e., make sure that none of the ERROR bits are set, and that the DAI is idle ([`STATUS.DAI_IDLE`](registers.md#status)). 2. Set up the periodic background checks: - - Choose whether to enable periodic [background checks](#partition-checks) by programming nonzero mask values to [`INTEGRITY_CHECK_PERIOD`](../data/otp_ctrl.hjson#integrity_check_period) and [`CONSISTENCY_CHECK_PERIOD`](../data/otp_ctrl.hjson#consistency_check_period). - - Choose whether such checks shall be subject to a timeout by programming a nonzero timeout cycle count to [`CHECK_TIMEOUT`](../data/otp_ctrl.hjson#check_timeout). - - It is recommended to lock down the background check registers via [`CHECK_REGWEN`](../data/otp_ctrl.hjson#check_regwen), once the background checks have been set up. + - Choose whether to enable periodic [background checks](#partition-checks) by programming nonzero mask values to [`INTEGRITY_CHECK_PERIOD`](registers.md#integrity_check_period) and [`CONSISTENCY_CHECK_PERIOD`](registers.md#consistency_check_period). + - Choose whether such checks shall be subject to a timeout by programming a nonzero timeout cycle count to [`CHECK_TIMEOUT`](registers.md#check_timeout). + - It is recommended to lock down the background check registers via [`CHECK_REGWEN`](registers.md#check_regwen), once the background checks have been set up. -If needed, one-off integrity and consistency checks can be triggered via [`CHECK_TRIGGER`](../data/otp_ctrl.hjson#check_trigger). -If this functionality is not needed, it is recommended to lock down the trigger register via [`CHECK_TRIGGER_REGWEN`](../data/otp_ctrl.hjson#check_trigger_regwen). +If needed, one-off integrity and consistency checks can be triggered via [`CHECK_TRIGGER`](registers.md#check_trigger). +If this functionality is not needed, it is recommended to lock down the trigger register via [`CHECK_TRIGGER_REGWEN`](registers.md#check_trigger_regwen). -Later on during the boot process, SW may also choose to block read access to the CREATOR_SW_CFG or OWNER_SW_CFG partitions at runtime via [`CREATOR_SW_CFG_READ_LOCK`](../data/otp_ctrl.hjson#creator_sw_cfg_read_lock) and [`OWNER_SW_CFG_READ_LOCK`](../data/otp_ctrl.hjson#owner_sw_cfg_read_lock). +Later on during the boot process, SW may also choose to block read access to the CREATOR_SW_CFG or OWNER_SW_CFG partitions at runtime via [`CREATOR_SW_CFG_READ_LOCK`](registers.md#creator_sw_cfg_read_lock) and [`OWNER_SW_CFG_READ_LOCK`](registers.md#owner_sw_cfg_read_lock). ### Reset Considerations @@ -38,7 +38,7 @@ Hence the OTP controller performs a blank check and returns an error if a write ### Potential Side-Effects on Flash via Life Cycle -It should be noted that the locked status of the partition holding the creator root key (i.e., the value of the [`SECRET2_DIGEST_0`](../data/otp_ctrl.hjson#secret2_digest_0)) determines the ID_STATUS of the device, which in turn determines SW accessibility of creator seed material in flash and OTP. +It should be noted that the locked status of the partition holding the creator root key (i.e., the value of the [`SECRET2_DIGEST_0`](registers.md#secret2_digest)) determines the ID_STATUS of the device, which in turn determines SW accessibility of creator seed material in flash and OTP. That means that creator-seed-related collateral needs to be provisioned to Flash **before** the OTP digest lockdown mechanism is triggered, since otherwise accessibility to the corresponding flash region is lost. See the [life cycle controller documentation](../../lc_ctrl/README.md#id-state-of-the-device) for more details. @@ -48,13 +48,13 @@ OTP has to be programmed via the Direct Access Interface, which is comprised of CSR Name | Description -------------------------------------|------------------------------------ -[`DIRECT_ACCESS_WDATA_0`](../data/otp_ctrl.hjson#direct_access_wdata_0) | Low 32bit word to be written. -[`DIRECT_ACCESS_WDATA_1`](../data/otp_ctrl.hjson#direct_access_wdata_1) | High 32bit word to be written. -[`DIRECT_ACCESS_RDATA_0`](../data/otp_ctrl.hjson#direct_access_rdata_0) | Low 32bit word that has been read. -[`DIRECT_ACCESS_RDATA_1`](../data/otp_ctrl.hjson#direct_access_rdata_1) | High 32bit word that has been read. -[`DIRECT_ACCESS_ADDRESS`](../data/otp_ctrl.hjson#direct_access_address) | byte address for the access. -[`DIRECT_ACCESS_CMD`](../data/otp_ctrl.hjson#direct_access_cmd) | Command register to trigger a read or a write access. -[`DIRECT_ACCESS_REGWEN`](../data/otp_ctrl.hjson#direct_access_regwen) | Write protection register for DAI. +[`DIRECT_ACCESS_WDATA_0`](registers.md#direct_access_wdata) | Low 32bit word to be written. +[`DIRECT_ACCESS_WDATA_1`](registers.md#direct_access_wdata) | High 32bit word to be written. +[`DIRECT_ACCESS_RDATA_0`](registers.md#direct_access_rdata) | Low 32bit word that has been read. +[`DIRECT_ACCESS_RDATA_1`](registers.md#direct_access_rdata) | High 32bit word that has been read. +[`DIRECT_ACCESS_ADDRESS`](registers.md#direct_access_address) | byte address for the access. +[`DIRECT_ACCESS_CMD`](registers.md#direct_access_cmd) | Command register to trigger a read or a write access. +[`DIRECT_ACCESS_REGWEN`](registers.md#direct_access_regwen) | Write protection register for DAI. See further below for a detailed [Memory Map](#direct-access-memory-map) of the address space accessible via the DAI. @@ -62,35 +62,35 @@ See further below for a detailed [Memory Map](#direct-access-memory-map) of the A typical readout sequence looks as follows: -1. Check whether the DAI is idle by reading the [`STATUS`](../data/otp_ctrl.hjson#status) register. -2. Write the byte address for the access to [`DIRECT_ACCESS_ADDRESS`](../data/otp_ctrl.hjson#direct_access_address). +1. Check whether the DAI is idle by reading the [`STATUS`](registers.md#status) register. +2. Write the byte address for the access to [`DIRECT_ACCESS_ADDRESS`](registers.md#direct_access_address). Note that the address is aligned with the granule, meaning that either 2 or 3 LSBs of the address are ignored, depending on whether the access granule is 32 or 64bit. -3. Trigger a read command by writing 0x1 to [`DIRECT_ACCESS_CMD`](../data/otp_ctrl.hjson#direct_access_cmd). -4. Poll the [`STATUS`](../data/otp_ctrl.hjson#status) until the DAI state goes back to idle. +3. Trigger a read command by writing 0x1 to [`DIRECT_ACCESS_CMD`](registers.md#direct_access_cmd). +4. Poll the [`STATUS`](registers.md#status) until the DAI state goes back to idle. Alternatively, the `otp_operation_done` interrupt can be enabled up to notify the processor once an access has completed. 5. If the status register flags a DAI error, additional handling is required (see [Section on Error handling](#error-handling)). -6. If the region accessed has a 32bit access granule, the 32bit chunk of read data can be read from [`DIRECT_ACCESS_RDATA_0`](../data/otp_ctrl.hjson#direct_access_rdata_0). -If the region accessed has a 64bit access granule, the 64bit chunk of read data can be read from the [`DIRECT_ACCESS_RDATA_0`](../data/otp_ctrl.hjson#direct_access_rdata_0) and [`DIRECT_ACCESS_RDATA_1`](../data/otp_ctrl.hjson#direct_access_rdata_1) registers. +6. If the region accessed has a 32bit access granule, the 32bit chunk of read data can be read from [`DIRECT_ACCESS_RDATA_0`](registers.md#direct_access_rdata). +If the region accessed has a 64bit access granule, the 64bit chunk of read data can be read from the [`DIRECT_ACCESS_RDATA_0`](registers.md#direct_access_rdata) and [`DIRECT_ACCESS_RDATA_1`](registers.md#direct_access_rdata) registers. 7. Go back to 1. and repeat until all data has been read. -The hardware will set [`DIRECT_ACCESS_REGWEN`](../data/otp_ctrl.hjson#direct_access_regwen) to 0x0 while an operation is pending in order to temporarily lock write access to the CSRs registers. +The hardware will set [`DIRECT_ACCESS_REGWEN`](registers.md#direct_access_regwen) to 0x0 while an operation is pending in order to temporarily lock write access to the CSRs registers. ### Programming Sequence A typical programming sequence looks as follows: -1. Check whether the DAI is idle by reading the [`STATUS`](../data/otp_ctrl.hjson#status) register. -2. If the region to be accessed has a 32bit access granule, place a 32bit chunk of data into [`DIRECT_ACCESS_WDATA_0`](../data/otp_ctrl.hjson#direct_access_wdata_0). -If the region to be accessed has a 64bit access granule, both the [`DIRECT_ACCESS_WDATA_0`](../data/otp_ctrl.hjson#direct_access_wdata_0) and [`DIRECT_ACCESS_WDATA_1`](../data/otp_ctrl.hjson#direct_access_wdata_1) registers have to be used. -3. Write the byte address for the access to [`DIRECT_ACCESS_ADDRESS`](../data/otp_ctrl.hjson#direct_access_address). +1. Check whether the DAI is idle by reading the [`STATUS`](registers.md#status) register. +2. If the region to be accessed has a 32bit access granule, place a 32bit chunk of data into [`DIRECT_ACCESS_WDATA_0`](registers.md#direct_access_wdata). +If the region to be accessed has a 64bit access granule, both the [`DIRECT_ACCESS_WDATA_0`](registers.md#direct_access_wdata) and [`DIRECT_ACCESS_WDATA_1`](registers.md#direct_access_wdata) registers have to be used. +3. Write the byte address for the access to [`DIRECT_ACCESS_ADDRESS`](registers.md#direct_access_address). Note that the address is aligned with the granule, meaning that either 2 or 3 LSBs of the address are ignored, depending on whether the access granule is 32 or 64bit. -4. Trigger a write command by writing 0x2 to [`DIRECT_ACCESS_CMD`](../data/otp_ctrl.hjson#direct_access_cmd). -5. Poll the [`STATUS`](../data/otp_ctrl.hjson#status) until the DAI state goes back to idle. +4. Trigger a write command by writing 0x2 to [`DIRECT_ACCESS_CMD`](registers.md#direct_access_cmd). +5. Poll the [`STATUS`](registers.md#status) until the DAI state goes back to idle. Alternatively, the `otp_operation_done` interrupt can be enabled up to notify the processor once an access has completed. 6. If the status register flags a DAI error, additional handling is required (see [Section on Error handling](#error-handling)). 7. Go back to 1. and repeat until all data has been written. -The hardware will set [`DIRECT_ACCESS_REGWEN`](../data/otp_ctrl.hjson#direct_access_regwen) to 0x0 while an operation is pending in order to temporarily lock write access to the CSRs registers. +The hardware will set [`DIRECT_ACCESS_REGWEN`](registers.md#direct_access_regwen) to 0x0 while an operation is pending in order to temporarily lock write access to the CSRs registers. Note that SW is responsible for keeping track of already programmed OTP word locations during the provisioning phase. **It is imperative that SW does not write the same word location twice**, since this can lead to ECC inconsistencies, thereby potentially rendering the device useless. @@ -99,14 +99,14 @@ Note that SW is responsible for keeping track of already programmed OTP word loc The hardware digest computation for the hardware and secret partitions can be triggered as follows: -1. Check whether the DAI is idle by reading the [`STATUS`](../data/otp_ctrl.hjson#status) register. -3. Write the partition base address to [`DIRECT_ACCESS_ADDRESS`](../data/otp_ctrl.hjson#direct_access_address). -4. Trigger a digest calculation command by writing 0x4 to [`DIRECT_ACCESS_CMD`](../data/otp_ctrl.hjson#direct_access_cmd). -5. Poll the [`STATUS`](../data/otp_ctrl.hjson#status) until the DAI state goes back to idle. +1. Check whether the DAI is idle by reading the [`STATUS`](registers.md#status) register. +3. Write the partition base address to [`DIRECT_ACCESS_ADDRESS`](registers.md#direct_access_address). +4. Trigger a digest calculation command by writing 0x4 to [`DIRECT_ACCESS_CMD`](registers.md#direct_access_cmd). +5. Poll the [`STATUS`](registers.md#status) until the DAI state goes back to idle. Alternatively, the `otp_operation_done` interrupt can be enabled up to notify the processor once an access has completed. 6. If the status register flags a DAI error, additional handling is required (see [Section on Error handling](#error-handling)). -The hardware will set [`DIRECT_ACCESS_REGWEN`](../data/otp_ctrl.hjson#direct_access_regwen) to 0x0 while an operation is pending in order to temporarily lock write access to the CSRs registers. +The hardware will set [`DIRECT_ACCESS_REGWEN`](registers.md#direct_access_regwen) to 0x0 while an operation is pending in order to temporarily lock write access to the CSRs registers. It should also be noted that the effect of locking a partition via the digest only takes effect **after** the next system reset. To prevent integrity check failures SW must therefore ensure that no more programming operations are issued to the affected partition after initiating the digest calculation sequence. @@ -203,17 +203,17 @@ For the HW_CFG and SECRET* partitions, this can be achieved as follows: 1. [Trigger](#digest-calculation-sequence) a digest calculation via the DAI. 2. [Read back](#readout-sequence) and verify the digest location via the DAI. -3. Perform a full-system reset and verify that the corresponding CSRs exposing the 64bit digest have been populated ([`HW_CFG_DIGEST_0`](../data/otp_ctrl.hjson#hw_cfg_digest_0), [`SECRET0_DIGEST_0`](../data/otp_ctrl.hjson#secret0_digest_0), [`SECRET1_DIGEST_0`](../data/otp_ctrl.hjson#secret1_digest_0) or [`SECRET2_DIGEST_0`](../data/otp_ctrl.hjson#secret2_digest_0)). +3. Perform a full-system reset and verify that the corresponding CSRs exposing the 64bit digest have been populated ([`HW_CFG_DIGEST_0`](registers.md#hw_cfg_digest), [`SECRET0_DIGEST_0`](registers.md#secret0_digest), [`SECRET1_DIGEST_0`](registers.md#secret1_digest) or [`SECRET2_DIGEST_0`](registers.md#secret2_digest)). It should be noted that locking only takes effect after a system reset since the affected partitions first have to re-sense the digest values. Hence, it is critical that SW ensures that no more data is written to the partition to be locked after triggering the hardware digest calculation. Otherwise, the device will likely be rendered inoperable as this can lead to permanent digest mismatch errors after system reboot. -For the [`CREATOR_SW_CFG`](../data/otp_ctrl.hjson#creator_sw_cfg) and [`OWNER_SW_CFG`](../data/otp_ctrl.hjson#owner_sw_cfg) partitions, the process is similar, but computation and programming of the digest is entirely up to software: +For the [`CREATOR_SW_CFG`](registers.md#creator_sw_cfg) and [`OWNER_SW_CFG`](registers.md#owner_sw_cfg) partitions, the process is similar, but computation and programming of the digest is entirely up to software: -1. Compute a 64bit digest over the relevant parts of the partition, and [program](#programming-sequence) that value to [`CREATOR_SW_CFG_DIGEST_0`](../data/otp_ctrl.hjson#creator_sw_cfg_digest_0) or [`OWNER_SW_CFG_DIGEST_0`](../data/otp_ctrl.hjson#owner_sw_cfg_digest_0) via the DAI. Note that digest accesses through the DAI have an access granule of 64bit. +1. Compute a 64bit digest over the relevant parts of the partition, and [program](#programming-sequence) that value to [`CREATOR_SW_CFG_DIGEST_0`](registers.md#creator_sw_cfg_digest) or [`OWNER_SW_CFG_DIGEST_0`](registers.md#owner_sw_cfg_digest) via the DAI. Note that digest accesses through the DAI have an access granule of 64bit. 2. [Read back](#readout-sequence) and verify the digest location via the DAI. -3. Perform a full-system reset and verify that the corresponding digest CSRs [`CREATOR_SW_CFG_DIGEST_0`](../data/otp_ctrl.hjson#creator_sw_cfg_digest_0) or [`OWNER_SW_CFG_DIGEST_0`](../data/otp_ctrl.hjson#owner_sw_cfg_digest_0) have been populated with the correct 64bit value. +3. Perform a full-system reset and verify that the corresponding digest CSRs [`CREATOR_SW_CFG_DIGEST_0`](registers.md#creator_sw_cfg_digest) or [`OWNER_SW_CFG_DIGEST_0`](registers.md#owner_sw_cfg_digest) have been populated with the correct 64bit value. Note that any unrecoverable errors during the programming steps, or mismatches during the read-back and verification steps indicate that the device might be malfunctioning (possibly due to fabrication defects) and hence the device may have to be scrapped. This is however rare and should not happen after fabrication testing. @@ -222,10 +222,6 @@ This is however rare and should not happen after fabrication testing. - [Device Interface Functions](../../../../sw/device/lib/dif/dif_otp_ctrl.h) -## Register Table - -* [Register Table](../data/otp_ctrl.hjson#registers) - # Additional Notes ## OTP IP Assumptions diff --git a/hw/ip/otp_ctrl/doc/registers.md b/hw/ip/otp_ctrl/doc/registers.md new file mode 100644 index 0000000000000..5ff0fa4079ddf --- /dev/null +++ b/hw/ip/otp_ctrl/doc/registers.md @@ -0,0 +1,1012 @@ +# Registers + + +## Summary of the **`core`** interface's registers + +| Name | Offset | Length | Description | +|:-----------------------------------------------------------------|:---------|---------:|:----------------------------------------------------------------------------------------------------| +| otp_ctrl.[`INTR_STATE`](#intr_state) | 0x0 | 4 | Interrupt State Register | +| otp_ctrl.[`INTR_ENABLE`](#intr_enable) | 0x4 | 4 | Interrupt Enable Register | +| otp_ctrl.[`INTR_TEST`](#intr_test) | 0x8 | 4 | Interrupt Test Register | +| otp_ctrl.[`ALERT_TEST`](#alert_test) | 0xc | 4 | Alert Test Register | +| otp_ctrl.[`STATUS`](#status) | 0x10 | 4 | OTP status register. | +| otp_ctrl.[`ERR_CODE`](#ERR_CODE) | 0x14 | 4 | This register holds information about error conditions that occurred in the agents | +| otp_ctrl.[`DIRECT_ACCESS_REGWEN`](#direct_access_regwen) | 0x18 | 4 | Register write enable for all direct access interface registers. | +| otp_ctrl.[`DIRECT_ACCESS_CMD`](#direct_access_cmd) | 0x1c | 4 | Command register for direct accesses. | +| otp_ctrl.[`DIRECT_ACCESS_ADDRESS`](#direct_access_address) | 0x20 | 4 | Address register for direct accesses. | +| otp_ctrl.[`DIRECT_ACCESS_WDATA_0`](#direct_access_wdata) | 0x24 | 4 | Write data for direct accesses. | +| otp_ctrl.[`DIRECT_ACCESS_WDATA_1`](#direct_access_wdata) | 0x28 | 4 | Write data for direct accesses. | +| otp_ctrl.[`DIRECT_ACCESS_RDATA_0`](#direct_access_rdata) | 0x2c | 4 | Read data for direct accesses. | +| otp_ctrl.[`DIRECT_ACCESS_RDATA_1`](#direct_access_rdata) | 0x30 | 4 | Read data for direct accesses. | +| otp_ctrl.[`CHECK_TRIGGER_REGWEN`](#check_trigger_regwen) | 0x34 | 4 | Register write enable for !!CHECK_TRIGGER. | +| otp_ctrl.[`CHECK_TRIGGER`](#check_trigger) | 0x38 | 4 | Command register for direct accesses. | +| otp_ctrl.[`CHECK_REGWEN`](#check_regwen) | 0x3c | 4 | Register write enable for !!INTEGRITY_CHECK_PERIOD and !!CONSISTENCY_CHECK_PERIOD. | +| otp_ctrl.[`CHECK_TIMEOUT`](#check_timeout) | 0x40 | 4 | Timeout value for the integrity and consistency checks. | +| otp_ctrl.[`INTEGRITY_CHECK_PERIOD`](#integrity_check_period) | 0x44 | 4 | This value specifies the maximum period that can be generated pseudo-randomly. | +| otp_ctrl.[`CONSISTENCY_CHECK_PERIOD`](#consistency_check_period) | 0x48 | 4 | This value specifies the maximum period that can be generated pseudo-randomly. | +| otp_ctrl.[`VENDOR_TEST_READ_LOCK`](#vendor_test_read_lock) | 0x4c | 4 | Runtime read lock for the VENDOR_TEST partition. | +| otp_ctrl.[`CREATOR_SW_CFG_READ_LOCK`](#creator_sw_cfg_read_lock) | 0x50 | 4 | Runtime read lock for the CREATOR_SW_CFG partition. | +| otp_ctrl.[`OWNER_SW_CFG_READ_LOCK`](#owner_sw_cfg_read_lock) | 0x54 | 4 | Runtime read lock for the OWNER_SW_CFG partition. | +| otp_ctrl.[`VENDOR_TEST_DIGEST_0`](#vendor_test_digest) | 0x58 | 4 | Integrity digest for the VENDOR_TEST partition. | +| otp_ctrl.[`VENDOR_TEST_DIGEST_1`](#vendor_test_digest) | 0x5c | 4 | Integrity digest for the VENDOR_TEST partition. | +| otp_ctrl.[`CREATOR_SW_CFG_DIGEST_0`](#creator_sw_cfg_digest) | 0x60 | 4 | Integrity digest for the CREATOR_SW_CFG partition. | +| otp_ctrl.[`CREATOR_SW_CFG_DIGEST_1`](#creator_sw_cfg_digest) | 0x64 | 4 | Integrity digest for the CREATOR_SW_CFG partition. | +| otp_ctrl.[`OWNER_SW_CFG_DIGEST_0`](#owner_sw_cfg_digest) | 0x68 | 4 | Integrity digest for the OWNER_SW_CFG partition. | +| otp_ctrl.[`OWNER_SW_CFG_DIGEST_1`](#owner_sw_cfg_digest) | 0x6c | 4 | Integrity digest for the OWNER_SW_CFG partition. | +| otp_ctrl.[`HW_CFG_DIGEST_0`](#hw_cfg_digest) | 0x70 | 4 | Integrity digest for the HW_CFG partition. | +| otp_ctrl.[`HW_CFG_DIGEST_1`](#hw_cfg_digest) | 0x74 | 4 | Integrity digest for the HW_CFG partition. | +| otp_ctrl.[`SECRET0_DIGEST_0`](#secret0_digest) | 0x78 | 4 | Integrity digest for the SECRET0 partition. | +| otp_ctrl.[`SECRET0_DIGEST_1`](#secret0_digest) | 0x7c | 4 | Integrity digest for the SECRET0 partition. | +| otp_ctrl.[`SECRET1_DIGEST_0`](#secret1_digest) | 0x80 | 4 | Integrity digest for the SECRET1 partition. | +| otp_ctrl.[`SECRET1_DIGEST_1`](#secret1_digest) | 0x84 | 4 | Integrity digest for the SECRET1 partition. | +| otp_ctrl.[`SECRET2_DIGEST_0`](#secret2_digest) | 0x88 | 4 | Integrity digest for the SECRET2 partition. | +| otp_ctrl.[`SECRET2_DIGEST_1`](#secret2_digest) | 0x8c | 4 | Integrity digest for the SECRET2 partition. | +| otp_ctrl.[`SW_CFG_WINDOW`](#sw_cfg_window) | 0x1000 | 2048 | Any read to this window directly maps to the corresponding offset in the creator and owner software | + +## INTR_STATE +Interrupt State Register +- Offset: `0x0` +- Reset default: `0x0` +- Reset mask: `0x3` + +### Fields + +```wavejson +{"reg": [{"name": "otp_operation_done", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "otp_error", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"bits": 30}], "config": {"lanes": 1, "fontsize": 10, "vspace": 200}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------------------|:-----------------------------------------------------------------------------------------------------------------| +| 31:2 | | | | Reserved | +| 1 | rw1c | 0x0 | otp_error | An error has occurred in the OTP controller. Check the [`ERR_CODE`](#err_code) register to get more information. | +| 0 | rw1c | 0x0 | otp_operation_done | A direct access command or digest calculation operation has completed. | + +## INTR_ENABLE +Interrupt Enable Register +- Offset: `0x4` +- Reset default: `0x0` +- Reset mask: `0x3` + +### Fields + +```wavejson +{"reg": [{"name": "otp_operation_done", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "otp_error", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 30}], "config": {"lanes": 1, "fontsize": 10, "vspace": 200}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------------------|:-----------------------------------------------------------------------------| +| 31:2 | | | | Reserved | +| 1 | rw | 0x0 | otp_error | Enable interrupt when [`INTR_STATE.otp_error`](#intr_state) is set. | +| 0 | rw | 0x0 | otp_operation_done | Enable interrupt when [`INTR_STATE.otp_operation_done`](#intr_state) is set. | + +## INTR_TEST +Interrupt Test Register +- Offset: `0x8` +- Reset default: `0x0` +- Reset mask: `0x3` + +### Fields + +```wavejson +{"reg": [{"name": "otp_operation_done", "bits": 1, "attr": ["wo"], "rotate": -90}, {"name": "otp_error", "bits": 1, "attr": ["wo"], "rotate": -90}, {"bits": 30}], "config": {"lanes": 1, "fontsize": 10, "vspace": 200}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------------------|:----------------------------------------------------------------------| +| 31:2 | | | | Reserved | +| 1 | wo | 0x0 | otp_error | Write 1 to force [`INTR_STATE.otp_error`](#intr_state) to 1. | +| 0 | wo | 0x0 | otp_operation_done | Write 1 to force [`INTR_STATE.otp_operation_done`](#intr_state) to 1. | + +## ALERT_TEST +Alert Test Register +- Offset: `0xc` +- Reset default: `0x0` +- Reset mask: `0x1f` + +### Fields + +```wavejson +{"reg": [{"name": "fatal_macro_error", "bits": 1, "attr": ["wo"], "rotate": -90}, {"name": "fatal_check_error", "bits": 1, "attr": ["wo"], "rotate": -90}, {"name": "fatal_bus_integ_error", "bits": 1, "attr": ["wo"], "rotate": -90}, {"name": "fatal_prim_otp_alert", "bits": 1, "attr": ["wo"], "rotate": -90}, {"name": "recov_prim_otp_alert", "bits": 1, "attr": ["wo"], "rotate": -90}, {"bits": 27}], "config": {"lanes": 1, "fontsize": 10, "vspace": 230}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:----------------------|:-------------------------------------------------| +| 31:5 | | | | Reserved | +| 4 | wo | 0x0 | recov_prim_otp_alert | Write 1 to trigger one alert event of this kind. | +| 3 | wo | 0x0 | fatal_prim_otp_alert | Write 1 to trigger one alert event of this kind. | +| 2 | wo | 0x0 | fatal_bus_integ_error | Write 1 to trigger one alert event of this kind. | +| 1 | wo | 0x0 | fatal_check_error | Write 1 to trigger one alert event of this kind. | +| 0 | wo | 0x0 | fatal_macro_error | Write 1 to trigger one alert event of this kind. | + +## STATUS +OTP status register. +- Offset: `0x10` +- Reset default: `0x0` +- Reset mask: `0x1ffff` + +### Fields + +```wavejson +{"reg": [{"name": "VENDOR_TEST_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "CREATOR_SW_CFG_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "OWNER_SW_CFG_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "HW_CFG_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "SECRET0_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "SECRET1_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "SECRET2_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "LIFE_CYCLE_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "DAI_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "LCI_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "TIMEOUT_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "LFSR_FSM_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "SCRAMBLING_FSM_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "KEY_DERIV_FSM_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "BUS_INTEG_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "DAI_IDLE", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "CHECK_PENDING", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 15}], "config": {"lanes": 1, "fontsize": 10, "vspace": 220}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------| +| 31:17 | | | | Reserved | +| 16 | ro | 0x0 | CHECK_PENDING | Set to 1 if an integrity or consistency check triggered by the LFSR timer or via [`CHECK_TRIGGER`](#check_trigger) is pending. | +| 15 | ro | 0x0 | DAI_IDLE | Set to 1 if the DAI is idle and ready to accept commands. | +| 14 | ro | 0x0 | BUS_INTEG_ERROR | This bit is set to 1 if a fatal bus integrity fault is detected. This error triggers a fatal_bus_integ_error alert. | +| 13 | ro | 0x0 | KEY_DERIV_FSM_ERROR | Set to 1 if the key derivation FSM has reached an invalid state. This raises an fatal_check_error alert and is an unrecoverable error condition. | +| 12 | ro | 0x0 | SCRAMBLING_FSM_ERROR | Set to 1 if the scrambling datapath FSM has reached an invalid state. This raises an fatal_check_error alert and is an unrecoverable error condition. | +| 11 | ro | 0x0 | LFSR_FSM_ERROR | Set to 1 if the LFSR timer FSM has reached an invalid state. This raises an fatal_check_error alert and is an unrecoverable error condition. | +| 10 | ro | 0x0 | TIMEOUT_ERROR | Set to 1 if an integrity or consistency check times out. This raises an fatal_check_error alert and is an unrecoverable error condition. | +| 9 | ro | 0x0 | LCI_ERROR | Set to 1 if an error occurred in the LCI. If set to 1, SW should check the [`ERR_CODE`](#err_code) register at the corresponding index. | +| 8 | ro | 0x0 | DAI_ERROR | Set to 1 if an error occurred in the DAI. If set to 1, SW should check the [`ERR_CODE`](#err_code) register at the corresponding index. | +| 7 | ro | 0x0 | LIFE_CYCLE_ERROR | Set to 1 if an error occurred in this partition. If set to 1, SW should check the [`ERR_CODE`](#err_code) register at the corresponding index. | +| 6 | ro | 0x0 | SECRET2_ERROR | Set to 1 if an error occurred in this partition. If set to 1, SW should check the [`ERR_CODE`](#err_code) register at the corresponding index. | +| 5 | ro | 0x0 | SECRET1_ERROR | Set to 1 if an error occurred in this partition. If set to 1, SW should check the [`ERR_CODE`](#err_code) register at the corresponding index. | +| 4 | ro | 0x0 | SECRET0_ERROR | Set to 1 if an error occurred in this partition. If set to 1, SW should check the [`ERR_CODE`](#err_code) register at the corresponding index. | +| 3 | ro | 0x0 | HW_CFG_ERROR | Set to 1 if an error occurred in this partition. If set to 1, SW should check the [`ERR_CODE`](#err_code) register at the corresponding index. | +| 2 | ro | 0x0 | OWNER_SW_CFG_ERROR | Set to 1 if an error occurred in this partition. If set to 1, SW should check the [`ERR_CODE`](#err_code) register at the corresponding index. | +| 1 | ro | 0x0 | CREATOR_SW_CFG_ERROR | Set to 1 if an error occurred in this partition. If set to 1, SW should check the [`ERR_CODE`](#err_code) register at the corresponding index. | +| 0 | ro | 0x0 | VENDOR_TEST_ERROR | Set to 1 if an error occurred in this partition. If set to 1, SW should check the [`ERR_CODE`](#err_code) register at the corresponding index. | + +## ERR_CODE +This register holds information about error conditions that occurred in the agents +interacting with the OTP macro via the internal bus. The error codes should be checked +if the partitions, DAI or LCI flag an error in the [`STATUS`](#status) register, or when an +[`INTR_STATE.otp_error`](#intr_state) has been triggered. Note that all errors trigger an otp_error +interrupt, and in addition some errors may trigger either an fatal_macro_error or an +fatal_check_error alert. +- Offset: `0x14` +- Reset default: `0x0` +- Reset mask: `0x3fffffff` + +### Fields + +```wavejson +{"reg": [{"name": "ERR_CODE_0", "bits": 3, "attr": ["ro"], "rotate": -90}, {"name": "ERR_CODE_1", "bits": 3, "attr": ["ro"], "rotate": -90}, {"name": "ERR_CODE_2", "bits": 3, "attr": ["ro"], "rotate": -90}, {"name": "ERR_CODE_3", "bits": 3, "attr": ["ro"], "rotate": -90}, {"name": "ERR_CODE_4", "bits": 3, "attr": ["ro"], "rotate": -90}, {"name": "ERR_CODE_5", "bits": 3, "attr": ["ro"], "rotate": -90}, {"name": "ERR_CODE_6", "bits": 3, "attr": ["ro"], "rotate": -90}, {"name": "ERR_CODE_7", "bits": 3, "attr": ["ro"], "rotate": -90}, {"name": "ERR_CODE_8", "bits": 3, "attr": ["ro"], "rotate": -90}, {"name": "ERR_CODE_9", "bits": 3, "attr": ["ro"], "rotate": -90}, {"bits": 2}], "config": {"lanes": 1, "fontsize": 10, "vspace": 120}} +``` + +| Bits | Type | Reset | Name | +|:------:|:------:|:-------:|:------------------------------------| +| 31:30 | | | Reserved | +| 29:27 | ro | 0x0 | [ERR_CODE_9](#err_code--err_code_9) | +| 26:24 | ro | 0x0 | [ERR_CODE_8](#err_code--err_code_8) | +| 23:21 | ro | 0x0 | [ERR_CODE_7](#err_code--err_code_7) | +| 20:18 | ro | 0x0 | [ERR_CODE_6](#err_code--err_code_6) | +| 17:15 | ro | 0x0 | [ERR_CODE_5](#err_code--err_code_5) | +| 14:12 | ro | 0x0 | [ERR_CODE_4](#err_code--err_code_4) | +| 11:9 | ro | 0x0 | [ERR_CODE_3](#err_code--err_code_3) | +| 8:6 | ro | 0x0 | [ERR_CODE_2](#err_code--err_code_2) | +| 5:3 | ro | 0x0 | [ERR_CODE_1](#err_code--err_code_1) | +| 2:0 | ro | 0x0 | [ERR_CODE_0](#err_code--err_code_0) | + +### ERR_CODE . ERR_CODE_9 + +| Value | Name | Description | +|:--------|:------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0x0 | NO_ERROR | No error condition has occurred. | +| 0x1 | MACRO_ERROR | Returned if the OTP macro command was invalid or did not complete successfully due to a macro malfunction. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_macro_error alert. | +| 0x2 | MACRO_ECC_CORR_ERROR | A correctable ECC error has occured during an OTP read operation. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x3 | MACRO_ECC_UNCORR_ERROR | An uncorrectable ECC error has occurred during an OTP read operation. This error should never occur during normal operation and is not recoverable. If this error is present this may be a sign that the device is malfunctioning. This error triggers an fatal_macro_error alert. | +| 0x4 | MACRO_WRITE_BLANK_ERROR | This error is returned if a programming operation attempted to clear a bit that has previously been programmed to 1. The corresponding controller automatically recovers from this error when issuing a new command. Note however that the affected OTP word may be left in an inconsistent state if this error occurs. This can cause several issues when the word is accessed again (either as part of a regular read operation, as part of the readout at boot, or as part of a background check). It is important that SW ensures that each word is only written once, since this can render the device useless. | +| 0x5 | ACCESS_ERROR | This error indicates that a locked memory region has been accessed. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x6 | CHECK_FAIL_ERROR | An ECC, integrity or consistency mismatch has been detected in the buffer registers. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_check_error alert. | +| 0x7 | FSM_STATE_ERROR | The FSM of the corresponding controller has reached an invalid state, or the FSM has been moved into a terminal error state due to an escalation action via lc_escalate_en_i. This error should never occur during normal operation and is not recoverable. If this error is present, this is a sign that the device has fallen victim to an invasive attack. This error triggers an fatal_check_error alert. | + + +### ERR_CODE . ERR_CODE_8 + +| Value | Name | Description | +|:--------|:------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0x0 | NO_ERROR | No error condition has occurred. | +| 0x1 | MACRO_ERROR | Returned if the OTP macro command was invalid or did not complete successfully due to a macro malfunction. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_macro_error alert. | +| 0x2 | MACRO_ECC_CORR_ERROR | A correctable ECC error has occured during an OTP read operation. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x3 | MACRO_ECC_UNCORR_ERROR | An uncorrectable ECC error has occurred during an OTP read operation. This error should never occur during normal operation and is not recoverable. If this error is present this may be a sign that the device is malfunctioning. This error triggers an fatal_macro_error alert. | +| 0x4 | MACRO_WRITE_BLANK_ERROR | This error is returned if a programming operation attempted to clear a bit that has previously been programmed to 1. The corresponding controller automatically recovers from this error when issuing a new command. Note however that the affected OTP word may be left in an inconsistent state if this error occurs. This can cause several issues when the word is accessed again (either as part of a regular read operation, as part of the readout at boot, or as part of a background check). It is important that SW ensures that each word is only written once, since this can render the device useless. | +| 0x5 | ACCESS_ERROR | This error indicates that a locked memory region has been accessed. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x6 | CHECK_FAIL_ERROR | An ECC, integrity or consistency mismatch has been detected in the buffer registers. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_check_error alert. | +| 0x7 | FSM_STATE_ERROR | The FSM of the corresponding controller has reached an invalid state, or the FSM has been moved into a terminal error state due to an escalation action via lc_escalate_en_i. This error should never occur during normal operation and is not recoverable. If this error is present, this is a sign that the device has fallen victim to an invasive attack. This error triggers an fatal_check_error alert. | + + +### ERR_CODE . ERR_CODE_7 + +| Value | Name | Description | +|:--------|:------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0x0 | NO_ERROR | No error condition has occurred. | +| 0x1 | MACRO_ERROR | Returned if the OTP macro command was invalid or did not complete successfully due to a macro malfunction. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_macro_error alert. | +| 0x2 | MACRO_ECC_CORR_ERROR | A correctable ECC error has occured during an OTP read operation. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x3 | MACRO_ECC_UNCORR_ERROR | An uncorrectable ECC error has occurred during an OTP read operation. This error should never occur during normal operation and is not recoverable. If this error is present this may be a sign that the device is malfunctioning. This error triggers an fatal_macro_error alert. | +| 0x4 | MACRO_WRITE_BLANK_ERROR | This error is returned if a programming operation attempted to clear a bit that has previously been programmed to 1. The corresponding controller automatically recovers from this error when issuing a new command. Note however that the affected OTP word may be left in an inconsistent state if this error occurs. This can cause several issues when the word is accessed again (either as part of a regular read operation, as part of the readout at boot, or as part of a background check). It is important that SW ensures that each word is only written once, since this can render the device useless. | +| 0x5 | ACCESS_ERROR | This error indicates that a locked memory region has been accessed. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x6 | CHECK_FAIL_ERROR | An ECC, integrity or consistency mismatch has been detected in the buffer registers. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_check_error alert. | +| 0x7 | FSM_STATE_ERROR | The FSM of the corresponding controller has reached an invalid state, or the FSM has been moved into a terminal error state due to an escalation action via lc_escalate_en_i. This error should never occur during normal operation and is not recoverable. If this error is present, this is a sign that the device has fallen victim to an invasive attack. This error triggers an fatal_check_error alert. | + + +### ERR_CODE . ERR_CODE_6 + +| Value | Name | Description | +|:--------|:------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0x0 | NO_ERROR | No error condition has occurred. | +| 0x1 | MACRO_ERROR | Returned if the OTP macro command was invalid or did not complete successfully due to a macro malfunction. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_macro_error alert. | +| 0x2 | MACRO_ECC_CORR_ERROR | A correctable ECC error has occured during an OTP read operation. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x3 | MACRO_ECC_UNCORR_ERROR | An uncorrectable ECC error has occurred during an OTP read operation. This error should never occur during normal operation and is not recoverable. If this error is present this may be a sign that the device is malfunctioning. This error triggers an fatal_macro_error alert. | +| 0x4 | MACRO_WRITE_BLANK_ERROR | This error is returned if a programming operation attempted to clear a bit that has previously been programmed to 1. The corresponding controller automatically recovers from this error when issuing a new command. Note however that the affected OTP word may be left in an inconsistent state if this error occurs. This can cause several issues when the word is accessed again (either as part of a regular read operation, as part of the readout at boot, or as part of a background check). It is important that SW ensures that each word is only written once, since this can render the device useless. | +| 0x5 | ACCESS_ERROR | This error indicates that a locked memory region has been accessed. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x6 | CHECK_FAIL_ERROR | An ECC, integrity or consistency mismatch has been detected in the buffer registers. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_check_error alert. | +| 0x7 | FSM_STATE_ERROR | The FSM of the corresponding controller has reached an invalid state, or the FSM has been moved into a terminal error state due to an escalation action via lc_escalate_en_i. This error should never occur during normal operation and is not recoverable. If this error is present, this is a sign that the device has fallen victim to an invasive attack. This error triggers an fatal_check_error alert. | + + +### ERR_CODE . ERR_CODE_5 + +| Value | Name | Description | +|:--------|:------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0x0 | NO_ERROR | No error condition has occurred. | +| 0x1 | MACRO_ERROR | Returned if the OTP macro command was invalid or did not complete successfully due to a macro malfunction. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_macro_error alert. | +| 0x2 | MACRO_ECC_CORR_ERROR | A correctable ECC error has occured during an OTP read operation. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x3 | MACRO_ECC_UNCORR_ERROR | An uncorrectable ECC error has occurred during an OTP read operation. This error should never occur during normal operation and is not recoverable. If this error is present this may be a sign that the device is malfunctioning. This error triggers an fatal_macro_error alert. | +| 0x4 | MACRO_WRITE_BLANK_ERROR | This error is returned if a programming operation attempted to clear a bit that has previously been programmed to 1. The corresponding controller automatically recovers from this error when issuing a new command. Note however that the affected OTP word may be left in an inconsistent state if this error occurs. This can cause several issues when the word is accessed again (either as part of a regular read operation, as part of the readout at boot, or as part of a background check). It is important that SW ensures that each word is only written once, since this can render the device useless. | +| 0x5 | ACCESS_ERROR | This error indicates that a locked memory region has been accessed. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x6 | CHECK_FAIL_ERROR | An ECC, integrity or consistency mismatch has been detected in the buffer registers. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_check_error alert. | +| 0x7 | FSM_STATE_ERROR | The FSM of the corresponding controller has reached an invalid state, or the FSM has been moved into a terminal error state due to an escalation action via lc_escalate_en_i. This error should never occur during normal operation and is not recoverable. If this error is present, this is a sign that the device has fallen victim to an invasive attack. This error triggers an fatal_check_error alert. | + + +### ERR_CODE . ERR_CODE_4 + +| Value | Name | Description | +|:--------|:------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0x0 | NO_ERROR | No error condition has occurred. | +| 0x1 | MACRO_ERROR | Returned if the OTP macro command was invalid or did not complete successfully due to a macro malfunction. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_macro_error alert. | +| 0x2 | MACRO_ECC_CORR_ERROR | A correctable ECC error has occured during an OTP read operation. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x3 | MACRO_ECC_UNCORR_ERROR | An uncorrectable ECC error has occurred during an OTP read operation. This error should never occur during normal operation and is not recoverable. If this error is present this may be a sign that the device is malfunctioning. This error triggers an fatal_macro_error alert. | +| 0x4 | MACRO_WRITE_BLANK_ERROR | This error is returned if a programming operation attempted to clear a bit that has previously been programmed to 1. The corresponding controller automatically recovers from this error when issuing a new command. Note however that the affected OTP word may be left in an inconsistent state if this error occurs. This can cause several issues when the word is accessed again (either as part of a regular read operation, as part of the readout at boot, or as part of a background check). It is important that SW ensures that each word is only written once, since this can render the device useless. | +| 0x5 | ACCESS_ERROR | This error indicates that a locked memory region has been accessed. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x6 | CHECK_FAIL_ERROR | An ECC, integrity or consistency mismatch has been detected in the buffer registers. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_check_error alert. | +| 0x7 | FSM_STATE_ERROR | The FSM of the corresponding controller has reached an invalid state, or the FSM has been moved into a terminal error state due to an escalation action via lc_escalate_en_i. This error should never occur during normal operation and is not recoverable. If this error is present, this is a sign that the device has fallen victim to an invasive attack. This error triggers an fatal_check_error alert. | + + +### ERR_CODE . ERR_CODE_3 + +| Value | Name | Description | +|:--------|:------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0x0 | NO_ERROR | No error condition has occurred. | +| 0x1 | MACRO_ERROR | Returned if the OTP macro command was invalid or did not complete successfully due to a macro malfunction. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_macro_error alert. | +| 0x2 | MACRO_ECC_CORR_ERROR | A correctable ECC error has occured during an OTP read operation. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x3 | MACRO_ECC_UNCORR_ERROR | An uncorrectable ECC error has occurred during an OTP read operation. This error should never occur during normal operation and is not recoverable. If this error is present this may be a sign that the device is malfunctioning. This error triggers an fatal_macro_error alert. | +| 0x4 | MACRO_WRITE_BLANK_ERROR | This error is returned if a programming operation attempted to clear a bit that has previously been programmed to 1. The corresponding controller automatically recovers from this error when issuing a new command. Note however that the affected OTP word may be left in an inconsistent state if this error occurs. This can cause several issues when the word is accessed again (either as part of a regular read operation, as part of the readout at boot, or as part of a background check). It is important that SW ensures that each word is only written once, since this can render the device useless. | +| 0x5 | ACCESS_ERROR | This error indicates that a locked memory region has been accessed. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x6 | CHECK_FAIL_ERROR | An ECC, integrity or consistency mismatch has been detected in the buffer registers. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_check_error alert. | +| 0x7 | FSM_STATE_ERROR | The FSM of the corresponding controller has reached an invalid state, or the FSM has been moved into a terminal error state due to an escalation action via lc_escalate_en_i. This error should never occur during normal operation and is not recoverable. If this error is present, this is a sign that the device has fallen victim to an invasive attack. This error triggers an fatal_check_error alert. | + + +### ERR_CODE . ERR_CODE_2 + +| Value | Name | Description | +|:--------|:------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0x0 | NO_ERROR | No error condition has occurred. | +| 0x1 | MACRO_ERROR | Returned if the OTP macro command was invalid or did not complete successfully due to a macro malfunction. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_macro_error alert. | +| 0x2 | MACRO_ECC_CORR_ERROR | A correctable ECC error has occured during an OTP read operation. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x3 | MACRO_ECC_UNCORR_ERROR | An uncorrectable ECC error has occurred during an OTP read operation. This error should never occur during normal operation and is not recoverable. If this error is present this may be a sign that the device is malfunctioning. This error triggers an fatal_macro_error alert. | +| 0x4 | MACRO_WRITE_BLANK_ERROR | This error is returned if a programming operation attempted to clear a bit that has previously been programmed to 1. The corresponding controller automatically recovers from this error when issuing a new command. Note however that the affected OTP word may be left in an inconsistent state if this error occurs. This can cause several issues when the word is accessed again (either as part of a regular read operation, as part of the readout at boot, or as part of a background check). It is important that SW ensures that each word is only written once, since this can render the device useless. | +| 0x5 | ACCESS_ERROR | This error indicates that a locked memory region has been accessed. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x6 | CHECK_FAIL_ERROR | An ECC, integrity or consistency mismatch has been detected in the buffer registers. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_check_error alert. | +| 0x7 | FSM_STATE_ERROR | The FSM of the corresponding controller has reached an invalid state, or the FSM has been moved into a terminal error state due to an escalation action via lc_escalate_en_i. This error should never occur during normal operation and is not recoverable. If this error is present, this is a sign that the device has fallen victim to an invasive attack. This error triggers an fatal_check_error alert. | + + +### ERR_CODE . ERR_CODE_1 + +| Value | Name | Description | +|:--------|:------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0x0 | NO_ERROR | No error condition has occurred. | +| 0x1 | MACRO_ERROR | Returned if the OTP macro command was invalid or did not complete successfully due to a macro malfunction. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_macro_error alert. | +| 0x2 | MACRO_ECC_CORR_ERROR | A correctable ECC error has occured during an OTP read operation. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x3 | MACRO_ECC_UNCORR_ERROR | An uncorrectable ECC error has occurred during an OTP read operation. This error should never occur during normal operation and is not recoverable. If this error is present this may be a sign that the device is malfunctioning. This error triggers an fatal_macro_error alert. | +| 0x4 | MACRO_WRITE_BLANK_ERROR | This error is returned if a programming operation attempted to clear a bit that has previously been programmed to 1. The corresponding controller automatically recovers from this error when issuing a new command. Note however that the affected OTP word may be left in an inconsistent state if this error occurs. This can cause several issues when the word is accessed again (either as part of a regular read operation, as part of the readout at boot, or as part of a background check). It is important that SW ensures that each word is only written once, since this can render the device useless. | +| 0x5 | ACCESS_ERROR | This error indicates that a locked memory region has been accessed. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x6 | CHECK_FAIL_ERROR | An ECC, integrity or consistency mismatch has been detected in the buffer registers. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_check_error alert. | +| 0x7 | FSM_STATE_ERROR | The FSM of the corresponding controller has reached an invalid state, or the FSM has been moved into a terminal error state due to an escalation action via lc_escalate_en_i. This error should never occur during normal operation and is not recoverable. If this error is present, this is a sign that the device has fallen victim to an invasive attack. This error triggers an fatal_check_error alert. | + + +### ERR_CODE . ERR_CODE_0 + +| Value | Name | Description | +|:--------|:------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0x0 | NO_ERROR | No error condition has occurred. | +| 0x1 | MACRO_ERROR | Returned if the OTP macro command was invalid or did not complete successfully due to a macro malfunction. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_macro_error alert. | +| 0x2 | MACRO_ECC_CORR_ERROR | A correctable ECC error has occured during an OTP read operation. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x3 | MACRO_ECC_UNCORR_ERROR | An uncorrectable ECC error has occurred during an OTP read operation. This error should never occur during normal operation and is not recoverable. If this error is present this may be a sign that the device is malfunctioning. This error triggers an fatal_macro_error alert. | +| 0x4 | MACRO_WRITE_BLANK_ERROR | This error is returned if a programming operation attempted to clear a bit that has previously been programmed to 1. The corresponding controller automatically recovers from this error when issuing a new command. Note however that the affected OTP word may be left in an inconsistent state if this error occurs. This can cause several issues when the word is accessed again (either as part of a regular read operation, as part of the readout at boot, or as part of a background check). It is important that SW ensures that each word is only written once, since this can render the device useless. | +| 0x5 | ACCESS_ERROR | This error indicates that a locked memory region has been accessed. The corresponding controller automatically recovers from this error when issuing a new command. | +| 0x6 | CHECK_FAIL_ERROR | An ECC, integrity or consistency mismatch has been detected in the buffer registers. This error should never occur during normal operation and is not recoverable. This error triggers an fatal_check_error alert. | +| 0x7 | FSM_STATE_ERROR | The FSM of the corresponding controller has reached an invalid state, or the FSM has been moved into a terminal error state due to an escalation action via lc_escalate_en_i. This error should never occur during normal operation and is not recoverable. If this error is present, this is a sign that the device has fallen victim to an invasive attack. This error triggers an fatal_check_error alert. | + + +## DIRECT_ACCESS_REGWEN +Register write enable for all direct access interface registers. +- Offset: `0x18` +- Reset default: `0x1` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "DIRECT_ACCESS_REGWEN", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 220}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 31:1 | | | | Reserved | +| 0 | ro | 0x1 | DIRECT_ACCESS_REGWEN | This bit is hardware-managed and only readable by software. The DAI sets this bit temporarily to 0 during an OTP operation such that the corresponding address and data registers cannot be modified while the operation is pending. | + +## DIRECT_ACCESS_CMD +Command register for direct accesses. +- Offset: `0x1c` +- Reset default: `0x0` +- Reset mask: `0x7` +- Register enable: [`DIRECT_ACCESS_REGWEN`](#direct_access_regwen) + +### Fields + +```wavejson +{"reg": [{"name": "RD", "bits": 1, "attr": ["r0w1c"], "rotate": -90}, {"name": "WR", "bits": 1, "attr": ["r0w1c"], "rotate": -90}, {"name": "DIGEST", "bits": 1, "attr": ["r0w1c"], "rotate": -90}, {"bits": 29}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 31:3 | | | | Reserved | +| 2 | r0w1c | 0x0 | DIGEST | Initiates the digest calculation and locking sequence for the partition specified by [`DIRECT_ACCESS_ADDRESS.`](#direct_access_address) | +| 1 | r0w1c | 0x0 | WR | Initiates a programming sequence that writes the data in [`DIRECT_ACCESS_WDATA_0`](#direct_access_wdata_0) and [`DIRECT_ACCESS_WDATA_1`](#direct_access_wdata_1) (for 64bit partitions) to the location specified by [`DIRECT_ACCESS_ADDRESS.`](#direct_access_address) | +| 0 | r0w1c | 0x0 | RD | Initiates a readout sequence that reads the location specified by [`DIRECT_ACCESS_ADDRESS.`](#direct_access_address) The command places the data read into [`DIRECT_ACCESS_RDATA_0`](#direct_access_rdata_0) and [`DIRECT_ACCESS_RDATA_1`](#direct_access_rdata_1) (for 64bit partitions). | + +## DIRECT_ACCESS_ADDRESS +Address register for direct accesses. +- Offset: `0x20` +- Reset default: `0x0` +- Reset mask: `0x7ff` +- Register enable: [`DIRECT_ACCESS_REGWEN`](#direct_access_regwen) + +### Fields + +```wavejson +{"reg": [{"name": "DIRECT_ACCESS_ADDRESS", "bits": 11, "attr": ["rw"], "rotate": -90}, {"bits": 21}], "config": {"lanes": 1, "fontsize": 10, "vspace": 230}} +``` + +| Bits | Type | Reset | Name | +|:------:|:------:|:-------:|:-----------------------------------------------------------------------| +| 31:11 | | | Reserved | +| 10:0 | rw | 0x0 | [DIRECT_ACCESS_ADDRESS](#direct_access_address--direct_access_address) | + +### DIRECT_ACCESS_ADDRESS . DIRECT_ACCESS_ADDRESS +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. + +For the digest calculation command, set this register to the partition base offset. + +## DIRECT_ACCESS_WDATA +Write data for direct accesses. +Hardware automatically determines the access granule (32bit or 64bit) based on which +partition is being written to. +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Instances + +| Name | Offset | +|:----------------------|:---------| +| DIRECT_ACCESS_WDATA_0 | 0x24 | +| DIRECT_ACCESS_WDATA_1 | 0x28 | + + +### Fields + +```wavejson +{"reg": [{"name": "DIRECT_ACCESS_WDATA", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:--------------------|:--------------| +| 31:0 | rw | 0x0 | DIRECT_ACCESS_WDATA | | + +## DIRECT_ACCESS_RDATA +Read data for direct accesses. +Hardware automatically determines the access granule (32bit or 64bit) based on which +partition is read from. +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Instances + +| Name | Offset | +|:----------------------|:---------| +| DIRECT_ACCESS_RDATA_0 | 0x2c | +| DIRECT_ACCESS_RDATA_1 | 0x30 | + + +### Fields + +```wavejson +{"reg": [{"name": "DIRECT_ACCESS_RDATA", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:--------------------|:--------------| +| 31:0 | ro | 0x0 | DIRECT_ACCESS_RDATA | | + +## CHECK_TRIGGER_REGWEN +Register write enable for [`CHECK_TRIGGER.`](#check_trigger) +- Offset: `0x34` +- Reset default: `0x1` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "CHECK_TRIGGER_REGWEN", "bits": 1, "attr": ["rw0c"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 220}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------------|:------------------------------------------------------------------------------------------------------------------------| +| 31:1 | | | | Reserved | +| 0 | rw0c | 0x1 | CHECK_TRIGGER_REGWEN | When cleared to 0, the [`CHECK_TRIGGER`](#check_trigger) register cannot be written anymore. Write 0 to clear this bit. | + +## CHECK_TRIGGER +Command register for direct accesses. +- Offset: `0x38` +- Reset default: `0x0` +- Reset mask: `0x3` +- Register enable: [`CHECK_TRIGGER_REGWEN`](#check_trigger_regwen) + +### Fields + +```wavejson +{"reg": [{"name": "INTEGRITY", "bits": 1, "attr": ["r0w1c"], "rotate": -90}, {"name": "CONSISTENCY", "bits": 1, "attr": ["r0w1c"], "rotate": -90}, {"bits": 30}], "config": {"lanes": 1, "fontsize": 10, "vspace": 130}} +``` + +| Bits | Type | Reset | Name | +|:------:|:------:|:-------:|:-------------------------------------------| +| 31:2 | | | Reserved | +| 1 | r0w1c | 0x0 | [CONSISTENCY](#check_trigger--consistency) | +| 0 | r0w1c | 0x0 | [INTEGRITY](#check_trigger--integrity) | + +### CHECK_TRIGGER . CONSISTENCY +Writing 1 to this bit triggers a consistency check. SW should monitor [`STATUS.CHECK_PENDING`](#status) +and wait until the check has been completed. If there are any errors, those will be flagged +in the [`STATUS`](#status) and [`ERR_CODE`](#err_code) registers, and via interrupts and alerts. + +### CHECK_TRIGGER . INTEGRITY +Writing 1 to this bit triggers an integrity check. SW should monitor [`STATUS.CHECK_PENDING`](#status) +and wait until the check has been completed. If there are any errors, those will be flagged +in the [`STATUS`](#status) and [`ERR_CODE`](#err_code) registers, and via the interrupts and alerts. + +## CHECK_REGWEN +Register write enable for [`INTEGRITY_CHECK_PERIOD`](#integrity_check_period) and [`CONSISTENCY_CHECK_PERIOD.`](#consistency_check_period) +- Offset: `0x3c` +- Reset default: `0x1` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "CHECK_REGWEN", "bits": 1, "attr": ["rw0c"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 140}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 31:1 | | | | Reserved | +| 0 | rw0c | 0x1 | CHECK_REGWEN | When cleared to 0, [`INTEGRITY_CHECK_PERIOD`](#integrity_check_period) and [`CONSISTENCY_CHECK_PERIOD`](#consistency_check_period) registers cannot be written anymore. Write 0 to clear this bit. | + +## CHECK_TIMEOUT +Timeout value for the integrity and consistency checks. +- Offset: `0x40` +- Reset default: `0x0` +- Reset mask: `0xffffffff` +- Register enable: [`CHECK_REGWEN`](#check_regwen) + +### Fields + +```wavejson +{"reg": [{"name": "CHECK_TIMEOUT", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | +|:------:|:------:|:-------:|:-----------------------------------------------| +| 31:0 | rw | 0x0 | [CHECK_TIMEOUT](#check_timeout--check_timeout) | + +### CHECK_TIMEOUT . CHECK_TIMEOUT +Timeout value in cycles for the for the integrity and consistency checks. If an integrity or consistency +check does not complete within the timeout window, an error will be flagged in the [`STATUS`](#status) register, +an otp_error interrupt will be raised, and an fatal_check_error alert will be sent out. The timeout should +be set to a large value to stay on the safe side. The maximum check time can be upper bounded by the +number of cycles it takes to readout, scramble and digest the entire OTP array. Since this amounts to +roughly 25k cycles, it is recommended to set this value to at least 100'000 cycles in order to stay on the +safe side. A value of zero disables the timeout mechanism (default). + +## INTEGRITY_CHECK_PERIOD +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. +- Offset: `0x44` +- Reset default: `0x0` +- Reset mask: `0xffffffff` +- Register enable: [`CHECK_REGWEN`](#check_regwen) + +### Fields + +```wavejson +{"reg": [{"name": "INTEGRITY_CHECK_PERIOD", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | +|:------:|:------:|:-------:|:--------------------------------------------------------------------------| +| 31:0 | rw | 0x0 | [INTEGRITY_CHECK_PERIOD](#integrity_check_period--integrity_check_period) | + +### INTEGRITY_CHECK_PERIOD . INTEGRITY_CHECK_PERIOD +The pseudo-random period is generated using a 40bit LFSR internally, and this register defines +the bit mask to be applied to the LFSR output in order to limit its range. The value of this +register is left shifted by 8bits and the lower bits are set to 8'hFF in order to form the 40bit mask. +A recommended value is 0x3_FFFF, corresponding to a maximum period of ~2.8s at 24MHz. +A value of zero disables the timer (default). Note that a one-off check can always be triggered via +[`CHECK_TRIGGER.INTEGRITY.`](#check_trigger) + +## CONSISTENCY_CHECK_PERIOD +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. +- Offset: `0x48` +- Reset default: `0x0` +- Reset mask: `0xffffffff` +- Register enable: [`CHECK_REGWEN`](#check_regwen) + +### Fields + +```wavejson +{"reg": [{"name": "CONSISTENCY_CHECK_PERIOD", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | +|:------:|:------:|:-------:|:--------------------------------------------------------------------------------| +| 31:0 | rw | 0x0 | [CONSISTENCY_CHECK_PERIOD](#consistency_check_period--consistency_check_period) | + +### CONSISTENCY_CHECK_PERIOD . CONSISTENCY_CHECK_PERIOD +The pseudo-random period is generated using a 40bit LFSR internally, and this register defines +the bit mask to be applied to the LFSR output in order to limit its range. The value of this +register is left shifted by 8bits and the lower bits are set to 8'hFF in order to form the 40bit mask. +A recommended value is 0x3FF_FFFF, corresponding to a maximum period of ~716s at 24MHz. +A value of zero disables the timer (default). Note that a one-off check can always be triggered via +[`CHECK_TRIGGER.CONSISTENCY.`](#check_trigger) + +## VENDOR_TEST_READ_LOCK +Runtime read lock for the VENDOR_TEST partition. +- Offset: `0x4c` +- Reset default: `0x1` +- Reset mask: `0x1` +- Register enable: [`DIRECT_ACCESS_REGWEN`](#direct_access_regwen) + +### Fields + +```wavejson +{"reg": [{"name": "VENDOR_TEST_READ_LOCK", "bits": 1, "attr": ["rw0c"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 230}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:----------------------|:--------------------------------------------------------------------------------------------------| +| 31:1 | | | | Reserved | +| 0 | rw0c | 0x1 | VENDOR_TEST_READ_LOCK | When cleared to 0, read access to the VENDOR_TEST partition is locked. Write 0 to clear this bit. | + +## CREATOR_SW_CFG_READ_LOCK +Runtime read lock for the CREATOR_SW_CFG partition. +- Offset: `0x50` +- Reset default: `0x1` +- Reset mask: `0x1` +- Register enable: [`DIRECT_ACCESS_REGWEN`](#direct_access_regwen) + +### Fields + +```wavejson +{"reg": [{"name": "CREATOR_SW_CFG_READ_LOCK", "bits": 1, "attr": ["rw0c"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 260}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------------------------|:-----------------------------------------------------------------------------------------------------| +| 31:1 | | | | Reserved | +| 0 | rw0c | 0x1 | CREATOR_SW_CFG_READ_LOCK | When cleared to 0, read access to the CREATOR_SW_CFG partition is locked. Write 0 to clear this bit. | + +## OWNER_SW_CFG_READ_LOCK +Runtime read lock for the OWNER_SW_CFG partition. +- Offset: `0x54` +- Reset default: `0x1` +- Reset mask: `0x1` +- Register enable: [`DIRECT_ACCESS_REGWEN`](#direct_access_regwen) + +### Fields + +```wavejson +{"reg": [{"name": "OWNER_SW_CFG_READ_LOCK", "bits": 1, "attr": ["rw0c"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 240}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-----------------------|:---------------------------------------------------------------------------------------------------| +| 31:1 | | | | Reserved | +| 0 | rw0c | 0x1 | OWNER_SW_CFG_READ_LOCK | When cleared to 0, read access to the OWNER_SW_CFG partition is locked. Write 0 to clear this bit. | + +## VENDOR_TEST_DIGEST +Integrity digest for the VENDOR_TEST partition. +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 VENDOR_TEST partition is locked and +the digest becomes visible in this CSR. +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Instances + +| Name | Offset | +|:---------------------|:---------| +| VENDOR_TEST_DIGEST_0 | 0x58 | +| VENDOR_TEST_DIGEST_1 | 0x5c | + + +### Fields + +```wavejson +{"reg": [{"name": "VENDOR_TEST_DIGEST", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------------------|:--------------| +| 31:0 | ro | 0x0 | VENDOR_TEST_DIGEST | | + +## CREATOR_SW_CFG_DIGEST +Integrity digest for the CREATOR_SW_CFG partition. +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. +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Instances + +| Name | Offset | +|:------------------------|:---------| +| CREATOR_SW_CFG_DIGEST_0 | 0x60 | +| CREATOR_SW_CFG_DIGEST_1 | 0x64 | + + +### Fields + +```wavejson +{"reg": [{"name": "CREATOR_SW_CFG_DIGEST", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:----------------------|:--------------| +| 31:0 | ro | 0x0 | CREATOR_SW_CFG_DIGEST | | + +## OWNER_SW_CFG_DIGEST +Integrity digest for the OWNER_SW_CFG partition. +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. +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Instances + +| Name | Offset | +|:----------------------|:---------| +| OWNER_SW_CFG_DIGEST_0 | 0x68 | +| OWNER_SW_CFG_DIGEST_1 | 0x6c | + + +### Fields + +```wavejson +{"reg": [{"name": "OWNER_SW_CFG_DIGEST", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:--------------------|:--------------| +| 31:0 | ro | 0x0 | OWNER_SW_CFG_DIGEST | | + +## HW_CFG_DIGEST +Integrity digest for the HW_CFG partition. +The integrity digest is 0 by default. The digest calculation can be triggered via the [`DIRECT_ACCESS_CMD.`](#direct_access_cmd) +After a reset, the digest then becomes visible in this CSR, and the corresponding partition becomes write-locked. +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Instances + +| Name | Offset | +|:----------------|:---------| +| HW_CFG_DIGEST_0 | 0x70 | +| HW_CFG_DIGEST_1 | 0x74 | + + +### Fields + +```wavejson +{"reg": [{"name": "HW_CFG_DIGEST", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:--------------|:--------------| +| 31:0 | ro | 0x0 | HW_CFG_DIGEST | | + +## SECRET0_DIGEST +Integrity digest for the SECRET0 partition. +The integrity digest is 0 by default. The digest calculation can be triggered via the [`DIRECT_ACCESS_CMD.`](#direct_access_cmd) +After a reset, the digest then becomes visible in this CSR, and the corresponding partition becomes write-locked. +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Instances + +| Name | Offset | +|:-----------------|:---------| +| SECRET0_DIGEST_0 | 0x78 | +| SECRET0_DIGEST_1 | 0x7c | + + +### Fields + +```wavejson +{"reg": [{"name": "SECRET0_DIGEST", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------|:--------------| +| 31:0 | ro | 0x0 | SECRET0_DIGEST | | + +## SECRET1_DIGEST +Integrity digest for the SECRET1 partition. +The integrity digest is 0 by default. The digest calculation can be triggered via the [`DIRECT_ACCESS_CMD.`](#direct_access_cmd) +After a reset, the digest then becomes visible in this CSR, and the corresponding partition becomes write-locked. +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Instances + +| Name | Offset | +|:-----------------|:---------| +| SECRET1_DIGEST_0 | 0x80 | +| SECRET1_DIGEST_1 | 0x84 | + + +### Fields + +```wavejson +{"reg": [{"name": "SECRET1_DIGEST", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------|:--------------| +| 31:0 | ro | 0x0 | SECRET1_DIGEST | | + +## SECRET2_DIGEST +Integrity digest for the SECRET2 partition. +The integrity digest is 0 by default. The digest calculation can be triggered via the [`DIRECT_ACCESS_CMD.`](#direct_access_cmd) +After a reset, the digest then becomes visible in this CSR, and the corresponding partition becomes write-locked. +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Instances + +| Name | Offset | +|:-----------------|:---------| +| SECRET2_DIGEST_0 | 0x88 | +| SECRET2_DIGEST_1 | 0x8c | + + +### Fields + +```wavejson +{"reg": [{"name": "SECRET2_DIGEST", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------|:--------------| +| 31:0 | ro | 0x0 | SECRET2_DIGEST | | + +## SW_CFG_WINDOW +Any read to this window directly maps to the corresponding offset in the creator and owner software +config partitions, and triggers an OTP readout of the bytes requested. Note that the transaction +will block until OTP readout has completed. + +- Word Aligned Offset Range: `0x1000`to`0x17fc` +- Size (words): `512` +- Access: `ro` +- Byte writes are *not* supported. + +## Summary of the **`prim`** interface's registers + +| Name | Offset | Length | Description | +|:-------------------------|:---------|---------:|:--------------| +| otp_ctrl.[`CSR0`](#csr0) | 0x0 | 4 | | +| otp_ctrl.[`CSR1`](#csr1) | 0x4 | 4 | | +| otp_ctrl.[`CSR2`](#csr2) | 0x8 | 4 | | +| otp_ctrl.[`CSR3`](#csr3) | 0xc | 4 | | +| otp_ctrl.[`CSR4`](#csr4) | 0x10 | 4 | | +| otp_ctrl.[`CSR5`](#csr5) | 0x14 | 4 | | +| otp_ctrl.[`CSR6`](#csr6) | 0x18 | 4 | | +| otp_ctrl.[`CSR7`](#csr7) | 0x1c | 4 | | + +## CSR0 + +- Offset: `0x0` +- Reset default: `0x0` +- Reset mask: `0x7ff3ff7` + +### Fields + +```wavejson +{"reg": [{"name": "field0", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "field1", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "field2", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 1}, {"name": "field3", "bits": 10, "attr": ["rw"], "rotate": 0}, {"bits": 2}, {"name": "field4", "bits": 11, "attr": ["rw"], "rotate": 0}, {"bits": 5}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------|:--------------| +| 31:27 | | | | Reserved | +| 26:16 | rw | 0x0 | field4 | | +| 15:14 | | | | Reserved | +| 13:4 | rw | 0x0 | field3 | | +| 3 | | | | Reserved | +| 2 | rw | 0x0 | field2 | | +| 1 | rw | 0x0 | field1 | | +| 0 | rw | 0x0 | field0 | | + +## CSR1 + +- Offset: `0x4` +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Fields + +```wavejson +{"reg": [{"name": "field0", "bits": 7, "attr": ["rw"], "rotate": 0}, {"name": "field1", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "field2", "bits": 7, "attr": ["rw"], "rotate": 0}, {"name": "field3", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "field4", "bits": 16, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------|:--------------| +| 31:16 | rw | 0x0 | field4 | | +| 15 | rw | 0x0 | field3 | | +| 14:8 | rw | 0x0 | field2 | | +| 7 | rw | 0x0 | field1 | | +| 6:0 | rw | 0x0 | field0 | | + +## CSR2 + +- Offset: `0x8` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "field0", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | field0 | | + +## CSR3 + +- Offset: `0xc` +- Reset default: `0x0` +- Reset mask: `0x7f3ff7` + +### Fields + +```wavejson +{"reg": [{"name": "field0", "bits": 3, "attr": ["rw1c"], "rotate": -90}, {"bits": 1}, {"name": "field1", "bits": 10, "attr": ["rw1c"], "rotate": 0}, {"bits": 2}, {"name": "field2", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "field3", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "field4", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "field5", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "field6", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "field7", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "field8", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 9}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------|:--------------| +| 31:23 | | | | Reserved | +| 22 | ro | 0x0 | field8 | | +| 21 | ro | 0x0 | field7 | | +| 20 | ro | 0x0 | field6 | | +| 19 | ro | 0x0 | field5 | | +| 18 | ro | 0x0 | field4 | | +| 17 | ro | 0x0 | field3 | | +| 16 | rw1c | 0x0 | field2 | | +| 15:14 | | | | Reserved | +| 13:4 | rw1c | 0x0 | field1 | | +| 3 | | | | Reserved | +| 2:0 | rw1c | 0x0 | field0 | | + +## CSR4 + +- Offset: `0x10` +- Reset default: `0x0` +- Reset mask: `0x73ff` + +### Fields + +```wavejson +{"reg": [{"name": "field0", "bits": 10, "attr": ["rw"], "rotate": 0}, {"bits": 2}, {"name": "field1", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "field2", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "field3", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 17}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------|:--------------| +| 31:15 | | | | Reserved | +| 14 | rw | 0x0 | field3 | | +| 13 | rw | 0x0 | field2 | | +| 12 | rw | 0x0 | field1 | | +| 11:10 | | | | Reserved | +| 9:0 | rw | 0x0 | field0 | | + +## CSR5 + +- Offset: `0x14` +- Reset default: `0x0` +- Reset mask: `0xffff3fff` + +### Fields + +```wavejson +{"reg": [{"name": "field0", "bits": 6, "attr": ["rw"], "rotate": 0}, {"name": "field1", "bits": 2, "attr": ["rw"], "rotate": -90}, {"name": "field2", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "field3", "bits": 3, "attr": ["ro"], "rotate": -90}, {"name": "field4", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "field5", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 2}, {"name": "field6", "bits": 16, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------|:--------------| +| 31:16 | rw | 0x0 | field6 | | +| 15:14 | | | | Reserved | +| 13 | ro | 0x0 | field5 | | +| 12 | ro | 0x0 | field4 | | +| 11:9 | ro | 0x0 | field3 | | +| 8 | ro | 0x0 | field2 | | +| 7:6 | rw | 0x0 | field1 | | +| 5:0 | rw | 0x0 | field0 | | + +## CSR6 + +- Offset: `0x18` +- Reset default: `0x0` +- Reset mask: `0xffff1bff` + +### Fields + +```wavejson +{"reg": [{"name": "field0", "bits": 10, "attr": ["rw"], "rotate": 0}, {"bits": 1}, {"name": "field1", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "field2", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 3}, {"name": "field3", "bits": 16, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------|:--------------| +| 31:16 | rw | 0x0 | field3 | | +| 15:13 | | | | Reserved | +| 12 | rw | 0x0 | field2 | | +| 11 | rw | 0x0 | field1 | | +| 10 | | | | Reserved | +| 9:0 | rw | 0x0 | field0 | | + +## CSR7 + +- Offset: `0x1c` +- Reset default: `0x0` +- Reset mask: `0xc73f` + +### Fields + +```wavejson +{"reg": [{"name": "field0", "bits": 6, "attr": ["ro"], "rotate": 0}, {"bits": 2}, {"name": "field1", "bits": 3, "attr": ["ro"], "rotate": -90}, {"bits": 3}, {"name": "field2", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "field3", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 16}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------|:--------------| +| 31:16 | | | | Reserved | +| 15 | ro | 0x0 | field3 | | +| 14 | ro | 0x0 | field2 | | +| 13:11 | | | | Reserved | +| 10:8 | ro | 0x0 | field1 | | +| 7:6 | | | | Reserved | +| 5:0 | ro | 0x0 | field0 | | + + + diff --git a/hw/ip/otp_ctrl/doc/theory_of_operation.md b/hw/ip/otp_ctrl/doc/theory_of_operation.md index 195da93a336b5..238f1a45a5346 100644 --- a/hw/ip/otp_ctrl/doc/theory_of_operation.md +++ b/hw/ip/otp_ctrl/doc/theory_of_operation.md @@ -47,7 +47,7 @@ The OTP controller for OpenTitan contains the seven logical partitions shown bel Generally speaking, the production life cycle of a device is split into 5 stages "Manufacturing" -> "Calibration and Testing" -> "Provisioning" -> "Mission" -> "RMA". OTP values are usually programmed during "Calibration and Testing", "Provisioning" and "RMA" stages, as explained below. -A detailed listing of all the items and the corresponding memory map can be found in the [Programmer's Guide](#programmers-guide)) further below. +A detailed listing of all the items and the corresponding memory map can be found in the [Programmer's Guide](programmers_guide.md)) further below. ### Calibration and Test @@ -228,201 +228,9 @@ The life cycle interface is used to update the life cycle state and transition c The commands are issued from the [life cycle controller](../../lc_ctrl/README.md), and similarly, successful or failed indications are also sent back to the life cycle controller. Similar to the functional interface, the life cycle controller allows only one update per power cycle, and after a requested transition reverts to an inert state until reboot. -For more details on how the software programs the OTP, please refer to the [Programmer's Guide](#programmers-guide)) further below. +For more details on how the software programs the OTP, please refer to the [Programmer's Guide](programmers_guide.md)) further below. -## 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). - -Parameter | Default (Max) | Top Earlgrey | Description -----------------------------|---------------|--------------|--------------- -`AlertAsyncOn` | 2'b11 | 2'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](#scrambling-datapath). -`RndCnstDigestConst` | (see RTL) | (see RTL) | Random digest finalization constants, to be used in the [scrambling datapath](#scrambling-datapath). -`RndCnstDigestIV` | (see RTL) | (see RTL) | Random digest initialization vectors, to be used in the [scrambling datapath](#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](../../lc_ctrl/README.md#conditional-transitions). - -### Signals - -* [Interface Tables](../data/otp_ctrl.hjson#interfaces) - -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](../../edn/README.md). - -#### 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](../../pwrmgr/README.md). - -#### 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](../../lc_ctrl/README.md) 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. -```wavejson -{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: - -```wavejson -{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](../../lc_ctrl/README.md#life-cycle-manufacturing-state-encodings) 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: - -```wavejson -{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](#scrambling-datapath). -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. - -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](../doc/otp_ctrl_key_req_ack.svg) - -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](#scrambling-datapath). -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. - -```wavejson -{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. -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](#interface-to-flash-scrambler). - -#### Hardware Config Bits - -The bits of the HW_CFG partition are output via the `otp_hw_cfg_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 partition, 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 partition has 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. - ## Design Details ### Block Diagram