Software APIs
lc_ctrl_transition_impl.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include <assert.h>
6 #include <stdbool.h>
7 
13 #include "sw/device/lib/testing/lc_ctrl_testutils.h"
14 #include "sw/device/lib/testing/test_framework/check.h"
15 
17 
18 #define LC_TOKEN_SIZE 16
19 
20 static dif_lc_ctrl_t lc;
21 
22 /**
23  * Track number of iterations of this C test.
24  *
25  * From the software / compiler's perspective, this is a constant (hence the
26  * `const` qualifier). However, the external DV testbench finds this symbol's
27  * address and modifies it via backdoor, to track how many transactions have
28  * been sent. Hence, we add the `volatile` keyword to prevent the compiler from
29  * optimizing it out.
30  * The `const` is needed to put it in the .rodata section, otherwise it gets
31  * placed in .data section in the main SRAM. We cannot backdoor write anything
32  * in SRAM at the start of the test because the CRT init code wipes it to 0s.
33  */
34 static volatile const uint8_t kTestIterationCount = 0x0;
35 
36 // LC exit token value for LC state transition.
37 static volatile const uint8_t kLcExitToken[LC_TOKEN_SIZE] = {
38  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
39  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
40 };
41 
42 /**
43  * Tests the state transition request handshake between LC_CTRL and OTP_CTRL.
44  *
45  * 1). OTP pre-load image with lc_count = `8`.
46  * 2). Backdoor write OTP's LC partition to `TestLocked1` state, and backdoor
47  * write OTP's `test_exit` token and `test_unlock` token to match the rand
48  * patterns.
49  * 3). `TestLocked1` state disabled CPU, so external testbench will drive JTAG
50  * interface to transit to `TestUnlocked2` state and increment the LC_CNT.
51  * 4). When LC_CTRL is ready, check LC_CNT and LC_STATE register.
52  * 5). Program LC state transition request to advance to `Dev` state.
53  * 6). Issue hard reset.
54  * 7). Wait for LC_CTRL is ready, then check if LC_STATE advanced to `Dev`
55  * state, and lc_count advanced to `9`.
56  * 8). Issue hard reset and override OTP's LC partition, and reset LC state to
57  * `TestLocked1` state.
58  * 9). Repeat the steps above in a few iterations.
59  *
60  * In summary, this sequence walks through the following LC states:
61  * "TestLocked1" -> "TestUnlocked2" -> "Dev"
62  */
63 
64 bool execute_lc_ctrl_transition_test(bool use_ext_clk) {
65  LOG_INFO("Start LC_CTRL transition test.");
66 
67  mmio_region_t lc_reg =
69  CHECK_DIF_OK(dif_lc_ctrl_init(lc_reg, &lc));
70 
71  LOG_INFO("Read and check LC state.");
72  dif_lc_ctrl_state_t curr_state;
73  CHECK_DIF_OK(dif_lc_ctrl_get_state(&lc, &curr_state));
74 
75  // The OTP preload image hardcodes the initial LC state transition count to 8.
76  // With each iteration of test, there are two LC_CTRL state transitions.
77  // And the first LC_CTRL state transition is done via external JTAG interface.
78  // `kTestIterationCount` starts with 1 in SystemVerilog.
79  const uint8_t kLcStateTransitionCount = 8 + 1 + (kTestIterationCount - 1) * 2;
80 
81  if (curr_state == kDifLcCtrlStateTestUnlocked2) {
82  // LC TestUnlocked2 is the intial test state for this sequence.
83  // The sequence will check if lc_count matches the preload value.
84  CHECK_STATUS_OK(
85  lc_ctrl_testutils_check_transition_count(&lc, kLcStateTransitionCount));
86 
87  // Request lc_state transfer to Dev state.
88  dif_lc_ctrl_token_t token;
89  for (int i = 0; i < LC_TOKEN_SIZE; i++) {
90  token.data[i] = kLcExitToken[i];
91  }
92  // Acquire the mutex, and release it after triggering the transition.
93  CHECK_DIF_OK(dif_lc_ctrl_mutex_try_acquire(&lc));
94  LOG_INFO("Acquired lc_ctrl mutex by software");
95  CHECK_DIF_OK(
96  dif_lc_ctrl_configure(&lc, kDifLcCtrlStateDev, use_ext_clk, &token),
97  "LC transition configuration failed!");
98  CHECK_DIF_OK(dif_lc_ctrl_transition(&lc), "LC transition failed!");
99  CHECK_DIF_OK(dif_lc_ctrl_mutex_release(&lc));
100  LOG_INFO("Waiting for LC transition done and reboot.");
102 
103  } else {
104  // LC Dev is the requested state from previous lc_state transition request.
105  // Once the sequence checks current state and count via CSRs, the test can
106  // exit successfully.
107  CHECK(curr_state == kDifLcCtrlStateDev, "State transition failed!");
108  CHECK_STATUS_OK(lc_ctrl_testutils_check_transition_count(
109  &lc, kLcStateTransitionCount + 1));
110  return true;
111  }
112 
113  return false;
114 }