| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| { |
| name: "otp_ctrl" |
| import_testplans: ["hw/dv/tools/dvsim/testplans/csr_testplan.hjson", |
| "hw/dv/tools/dvsim/testplans/mem_testplan.hjson", |
| "hw/dv/tools/dvsim/testplans/intr_test_testplan.hjson", |
| "hw/dv/tools/dvsim/testplans/alert_test_testplan.hjson", |
| "hw/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson", |
| "hw/dv/tools/dvsim/testplans/sec_cm_count_testplan.hjson", |
| "hw/dv/tools/dvsim/testplans/sec_cm_fsm_testplan.hjson", |
| "hw/dv/tools/dvsim/testplans/stress_all_with_reset_testplan.hjson", |
| "otp_ctrl_sec_cm_testplan.hjson"] |
| testpoints: [ |
| { |
| name: wake_up |
| desc: ''' |
| Wake_up test walks through otp_ctrl's power-on initialization, read, program, and |
| digest functionalities. |
| |
| - drive pwrmgr's request pin to trigger OTP initialization after reset, check status |
| after OTP initialization |
| - write all-ones to a random address within OTP partition 0, wait until this operation |
| completes |
| - read out the random selected write address, check if the readout value is all-ones |
| - trigger a digest calculation for a Software partition, check if the OtpError |
| interrupt is set |
| - trigger a digest calculation for a non-software partition, expect operation completes |
| without the OtpError interrupt |
| - read out secrets through the hardware interfaces |
| ''' |
| stage: V1 |
| tests: ["otp_ctrl_wake_up"] |
| } |
| { |
| name: smoke |
| desc: ''' |
| OTP_CTRL smoke test provisions and locks partitions. |
| |
| - drive pwrmgr's request pin to trigger OTP initialization after reset, check status |
| after OTP initialization |
| - randomly read out keys pertaining to `key_manager`, `flash`, `sram`, `otbn` |
| - randomly issue LC program request |
| - write random values to random addresses within each OTP partition |
| - read out the random selected write addresses, check if the readout values are expected |
| - during read and write operations, check if direct_access_regwen is correctly set by HW |
| - perform a system-level reset and check corresponding CSRs are set correctly |
| - lock all partitions except life_cycle by triggering digest calculations |
| - read back and verify the digest |
| - perform a system-level reset to verify the corresponding CSRs exposing the digests |
| have been populated |
| |
| **Checks**: |
| - Assertion checks to ensure vendor specific I/Os: `otp_vendor_test_status_o`, |
| `otp_vendor_test_ctrl_i`, `cio_test_o`, and `cio_test_en_o` are connected currently |
| with `lc_dft_en_i` On and Off. |
| ''' |
| stage: V1 |
| tests: ["otp_ctrl_smoke"] |
| } |
| { |
| name: dai_access_partition_walk |
| desc: ''' |
| Similar to UVM's memory walk test, this test ensures every address in each partition |
| can be accessed successfully via DAI and TLUL interfacs according to its access policy. |
| ''' |
| stage: V2 |
| tests: ["otp_ctrl_partition_walk"] |
| } |
| { |
| name: init_fail |
| desc: ''' |
| Based on OTP_CTRL smoke test, this test creates OTP_CTRL's initialization failure: |
| - write and read OTP memory via DAI interface |
| - randomly issue DAI digest command to lock HW partitions |
| - keep writing to OTP memory via DAI interface without asserting reset |
| - if digests are not locked, backdoor inject ECC correctable or uncorrectable errors |
| - issue reset and power initialization |
| - if the injected errors are all correctable errors, disable the `lc_bypass_chk_en` |
| after LC program request to create an LC partition check failure |
| |
| If fatal error is triggered, this test will check: |
| - OTP initialization failure triggers fatal alert |
| - `status`, `intr_state`, `err_code` CSRs reflect correct fatal error |
| |
| If OTP initialization finished without any fatal error, this test will check: |
| - OTP initialization finishes with power init output goes to 1 |
| - `status`, `intr_state`, `err_code` CSRs reflect ECC correctable error |
| ''' |
| stage: V2 |
| tests: ["otp_ctrl_init_fail"] |
| } |
| { |
| name: partition_check |
| desc: ''' |
| Randomly program the partition check related CSRs including: |
| - `check_timeout` |
| - `integrity_check_period` |
| - `consistency_check_period` |
| - `check_trigger` |
| |
| Create a failure scenario by randomly picking one of these three methods: |
| - inject ECC errors into the OTP macro via backdoor |
| - set the `check_timeout` CSR with a very small value |
| - write to a random OTP partition after digest is issued but before reset is asserted |
| |
| **Checks**: |
| - the corresponding alerts are triggered |
| - the error_code register is set correctly |
| Note that due to limited simulation time, for background checks, this test only write |
| random value that is less than 20 to the check period. |
| ''' |
| stage: V2 |
| tests: ["otp_ctrl_check_fail", "otp_ctrl_background_chks"] |
| } |
| { |
| name: regwen_during_otp_init |
| desc: ''' |
| The `direct_access_regwen` is a RO register which controls the write-enable of other |
| reigsters. It is not verified by the common CSR tests. HW sets it to 0 when the DAI |
| interface is busy. |
| |
| Stimulus and checks: |
| - randomly read `direct_access_regwen` and verify that it returns 0 during OTP |
| initialization |
| - verify that the writes to the registers controlled by it do not go through during OTP |
| initialization |
| ''' |
| stage: V2 |
| tests: ["otp_ctrl_regwen"] |
| } |
| { |
| name: partition_lock |
| desc: ''' |
| This test will cover two methods of locking read and write: digest calculation and CSR |
| write. After locking the partitions, issue read or program sequences and check if the |
| operations are locked correctly, and check if the `AccessError` is set. |
| ''' |
| stage: V2 |
| tests: ["otp_ctrl_dai_lock"] |
| } |
| { |
| name: interface_key_check |
| desc: ''' |
| OTP_CTRL will generate keys to `flash`, `sram`, and `otbn` upon their requests. |
| Based on the DAI access sequence, this test will run key requests sequence in |
| parallel, and check if correct keys are generated. |
| ''' |
| stage: V2 |
| tests: ["otp_ctrl_parallel_key_req"] |
| } |
| { |
| name: lc_interactions |
| desc: ''' |
| Verify the procotols between OTP_CTRL and LC_CTRL. Based on the DAI access sequence, |
| run the following sequences in parallel: |
| |
| - request a LC state transition via the programming interface |
| - enable the `lc_escalation_en` signal |
| |
| **Checks**: |
| - if the LC program request has `AccessError`, check the LC program response sets |
| the `error` bit to 1 |
| - if `lc_escalation_en` is enabled, verify that alert is triggered and OTP_CTRL entered |
| terminal state |
| ''' |
| stage: V2 |
| tests: ["otp_ctrl_parallel_lc_req", "otp_ctrl_parallel_lc_esc"] |
| } |
| { name: otp_dai_errors |
| desc: ''' |
| Based on the otp_dai_lock test, this test will randomly run the following OTP errors: |
| - DAI interface writes non-blank OTP address |
| - DAI interface accesses LC partition |
| - DAI interface writes HW digests |
| - DAI interface writes non-empty memory |
| |
| **Checks**: |
| - `err_code` and `status` CSRs |
| - `otp_error` interrupt |
| ''' |
| stage: V2 |
| tests: ["otp_ctrl_dai_errs"] |
| } |
| { name: otp_macro_errors |
| desc: ''' |
| Randomly run the following OTP errors: |
| - MacroError |
| - MacroEccCorrError |
| - MacroEccUncorrError |
| |
| **Checks**: |
| - `err_code` and `status` CSRs |
| - `otp_error` interrupt |
| - if the error is unrecoverable, verify that alert is triggered and OTP_CTRL entered |
| terminal state |
| ''' |
| stage: V2 |
| tests: ["otp_ctrl_macro_errs"] |
| } |
| { |
| name: test_access |
| desc: ''' |
| This test checks if the test access to OTP macro is connected correctly. |
| |
| **Stimulus and Checks**: |
| - Write and check read results from the prim_tl_i/o. |
| - Ensure no error or alert occurs from DUT. |
| ''' |
| stage: V2 |
| tests: ["otp_ctrl_test_access"] |
| } |
| { |
| name: stress_all |
| desc: ''' |
| - combine above sequences in one test to run sequentially, except csr sequence |
| - randomly add reset between each sequence |
| ''' |
| stage: V2 |
| tests: ["{name}_stress_all"] |
| } |
| { |
| name: sec_cm_additional_check |
| desc: ''' |
| Verify the outcome of injecting faults to security countermeasures. |
| |
| Stimulus: |
| As mentioned in `prim_count_check`, `prim_fsm_check` and `prim_double_lfsr_check`. |
| |
| Checks: |
| - Check the value of status register according to where the fault is injected. |
| - Check OTP_CTRL is locked after the fatal fault injection by trying to access OTP_CTRL |
| via dai, kdi, and lci interfaces. |
| ''' |
| stage: V2S |
| tests: ["otp_ctrl_sec_cm"] |
| } |
| { |
| name: otp_ctrl_low_freq_read |
| desc: ''' |
| This test checks if OTP's read operation can operate successfully in a low clock |
| frequency before the clock is calibrated. |
| |
| **Stimulus and Checks**: |
| - Configure OTP_CTRL's clock to 6MHz low frequency. |
| - Backdoor write OTP memory. |
| - Use DAI access to read each memory address and compare if the value is correct. |
| - If DAI address is in a SW partition, read and check again via TLUL interface. |
| ''' |
| stage: V3 |
| tests: ["otp_ctrl_low_freq_read"] |
| } |
| ] |
| |
| covergroups: [ |
| { |
| name: power_on_cg |
| desc: '''Covers the following conditions when OTP_CTRL finishes power-on initialization: |
| - whether `lc_escalation_en` is On |
| - whether any partition (except life cycle partition) is locked |
| ''' |
| } |
| { |
| name: flash_req_cg |
| desc: '''Covers whether secret1 partition is locked during `flash` data or address |
| request.''' |
| } |
| { |
| name: sram_req_cg |
| desc: '''Covers whether secret1 partition is locked during all `srams` key request.''' |
| } |
| { |
| name: otbn_req_cg |
| desc: '''Covers whether secret1 partition is locked during `otbn` key request.''' |
| } |
| { |
| name: lc_prog_cg |
| desc: '''Covers whether the error bit is set during LC program request.''' |
| } |
| { |
| name: keymgr_o_cg |
| desc: '''Covers the following conditions when scoreboard checks `keymgr_o` value: |
| - whether secret2 partition is locked |
| - whether `lc_seed_hw_rd_en_i` is On |
| ''' |
| } |
| { |
| name: req_dai_access_after_alert_cg |
| desc: '''Covers if sequence issued various DAI requests after any fatal alert is |
| triggered.''' |
| } |
| { |
| name: issue_checks_after_alert_cg |
| desc: '''Covers if sequence issued various OTP_CTRL's background checks after any fatal alert |
| is triggered.''' |
| } |
| { // TODO: this is from a wrapper class, confirm if this is the correct format |
| name: csr_rd_after_alert_cg |
| desc: '''Covers if the following CSRs are being read and the value is checked in scoreboard |
| after any fatal alert is triggered: |
| - unbuffered partitions' digest CSRs |
| - HW partition's digest CSRs |
| - secrets partitions' digest CSRs |
| - direct_access read data CSRs |
| - status CSR |
| - error_code CSR |
| ''' |
| } |
| { |
| name: dai_err_code_cg |
| desc: '''Covers all applicable error codes in DAI, and cross each error code with all |
| 7 partitions.''' |
| } |
| { |
| name: lci_err_code_cg |
| desc: '''Covers all applicable error codes in LCI.''' |
| } |
| { // TODO: this is an array of covergroups, confirm if this is the correct format |
| name: unbuf_err_code_cg |
| desc: '''This is an array of covergroups to cover all applicable error codes in three |
| unbuffered partitions.''' |
| } |
| { // TODO: this is an array of covergroups, confirm if this is the correct format |
| name: buf_err_code_cg |
| desc: '''This is an array of covergroups to cover all applicable error codes in five |
| buffered partitions.''' |
| } |
| { // TODO: this is an array of covergroups, confirm if this is the correct format |
| name: unbuf_access_lock_cg_wrap_cg |
| desc: '''This is an array of covergroups to cover lock conditions below in three |
| unbuffered partitions: |
| - the partition is write-locked |
| - the partition is read-locked |
| - the current operation type |
| Then cross the three coverpoints.''' |
| } |
| { |
| name: dai_access_secret2_cg |
| desc: '''Covers whether `lc_creator_seed_sw_rw_en` is On during any DAI accesses.''' |
| } |
| { // TODO: this is an array of covergroups, confirm if this is the correct format |
| name: status_csr_cg |
| desc: '''Covers the value of every bit in `status` CSR.''' |
| } |
| // The following covergroups are implemented in `otp_ctrl_cov_if.sv`. |
| { |
| name: lc_esc_en_condition_cg |
| desc: '''Covers the following conditions when `lc_escalation_en` is On: |
| - whether any key requests is in progress |
| - whether LC program reqeust is in progress |
| - whether DAI interface is busy |
| ''' |
| } |
| { |
| name: flash_data_req_condition_cg |
| desc: '''Covers the following conditions when `lc_escalation_en` is On: |
| - whether any key requests is in progress |
| - whether DAI interface is busy |
| - whether lc_esc_en is On |
| ''' |
| } |
| { |
| name: flash_addr_req_condition_cg |
| desc: '''Covers the following conditions when `lc_escalation_en` is On: |
| - whether any key requests is in progress |
| - whether DAI interface is busy |
| - whether lc_esc_en is On |
| ''' |
| } |
| { |
| name: sram_0_req_condition_cg |
| desc: '''Covers the following conditions when `lc_escalation_en` is On: |
| - whether any key requests is in progress |
| - whether DAI interface is busy |
| - whether lc_esc_en is On |
| ''' |
| } |
| { |
| name: sram_1_req_condition_cg |
| desc: '''Covers the following conditions when `lc_escalation_en` is On: |
| - whether any key requests is in progress |
| - whether DAI interface is busy |
| - whether lc_esc_en is On |
| ''' |
| } |
| { |
| name: otbn_req_condition_cg |
| desc: '''Covers the following conditions when `lc_escalation_en` is On: |
| - whether any key requests is in progress |
| - whether DAI interface is busy |
| - whether lc_esc_en is On |
| ''' |
| } |
| { |
| name: lc_prog_req_condition_cg |
| desc: '''Covers the following conditions when `lc_escalation_en` is On: |
| - whether any key requests is in progress |
| - whether DAI interface is busy |
| - whether lc_esc_en is On |
| ''' |
| } |
| ] |
| } |