opentitanlib/dif/
lc_ctrl.rs

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
5use anyhow::{Result, bail};
6use bitflags::bitflags;
7use serde::{Deserialize, Serialize};
8
9use crate::with_unknown;
10
11with_unknown! {
12    pub enum DifLcCtrlState: u32 [default = Self::StateInvalid] {
13        Raw = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateRaw ,
14        TestUnlocked0 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked0 ,
15        TestLocked0 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestLocked0 ,
16        TestUnlocked1 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked1 ,
17        TestLocked1 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestLocked1 ,
18        TestUnlocked2 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked2 ,
19        TestLocked2 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestLocked2 ,
20        TestUnlocked3 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked3 ,
21        TestLocked3 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestLocked3 ,
22        TestUnlocked4 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked4 ,
23        TestLocked4 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestLocked4 ,
24        TestUnlocked5 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked5 ,
25        TestLocked5 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestLocked5 ,
26        TestUnlocked6 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked6 ,
27        TestLocked6 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestLocked6 ,
28        TestUnlocked7 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked7 ,
29        Dev = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateDev ,
30        Prod = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateProd ,
31        ProdEnd = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateProdEnd ,
32        Rma = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateRma ,
33        Scrap = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateScrap ,
34        PostTransition = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStatePostTransition ,
35        Escalate = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateEscalate ,
36        StateInvalid = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateInvalid ,
37    }
38}
39
40pub struct DifLcCtrlTransCheck {
41    /// Whether the transition is valid.
42    pub valid: bool,
43    /// Whether the transition requires a token.
44    pub token: bool,
45}
46
47impl DifLcCtrlState {
48    pub fn from_redundant_encoding(encoding: u32) -> Result<Self> {
49        let base_encoding = encoding & 0x1fu32;
50        if base_encoding > u32::from(DifLcCtrlState::StateInvalid) {
51            bail!("Invalid life cycle state value.");
52        }
53        Ok(DifLcCtrlState(encoding & 0x1fu32))
54    }
55
56    /// Encode the given life cycle state in a redundant format where the
57    /// five-bit value is repeated six times.
58    pub fn redundant_encoding(&self) -> u32 {
59        let value: u32 = self.0;
60        assert_eq!(value & 0b11111, value);
61        (0..6).fold(0u32, |acc, _| (acc << 5) | value)
62    }
63
64    pub fn lc_state_to_str(self) -> &'static str {
65        match self {
66            DifLcCtrlState::Raw => "raw",
67            DifLcCtrlState::TestUnlocked0 => "test_unlocked0",
68            DifLcCtrlState::TestLocked0 => "test_locked0",
69            DifLcCtrlState::TestUnlocked1 => "test_unlocked1",
70            DifLcCtrlState::TestLocked1 => "test_locked1",
71            DifLcCtrlState::TestUnlocked2 => "test_unlocked2",
72            DifLcCtrlState::TestLocked2 => "test_locked2",
73            DifLcCtrlState::TestUnlocked3 => "test_unlocked3",
74            DifLcCtrlState::TestLocked3 => "test_locked3",
75            DifLcCtrlState::TestUnlocked4 => "test_unlocked4",
76            DifLcCtrlState::TestLocked4 => "test_locked4",
77            DifLcCtrlState::TestUnlocked5 => "test_unlocked5",
78            DifLcCtrlState::TestLocked5 => "test_locked5",
79            DifLcCtrlState::TestUnlocked6 => "test_unlocked6",
80            DifLcCtrlState::TestLocked6 => "test_locked6",
81            DifLcCtrlState::TestUnlocked7 => "test_unlocked7",
82            DifLcCtrlState::Dev => "dev",
83            DifLcCtrlState::Prod => "prod",
84            DifLcCtrlState::ProdEnd => "prod_end",
85            DifLcCtrlState::Rma => "rma",
86            DifLcCtrlState::Scrap => "scrap",
87            DifLcCtrlState::PostTransition => "post_transition",
88            DifLcCtrlState::Escalate => "escalate",
89            _ => "invalid",
90        }
91    }
92
93    pub fn parse_lc_state_str(lc_state_str: &str) -> Result<Self> {
94        match lc_state_str {
95            "raw" => Ok(DifLcCtrlState::Raw),
96            "test_unlocked0" => Ok(DifLcCtrlState::TestUnlocked0),
97            "test_locked0" => Ok(DifLcCtrlState::TestLocked0),
98            "test_unlocked1" => Ok(DifLcCtrlState::TestUnlocked1),
99            "test_locked1" => Ok(DifLcCtrlState::TestLocked1),
100            "test_unlocked2" => Ok(DifLcCtrlState::TestUnlocked2),
101            "test_locked2" => Ok(DifLcCtrlState::TestLocked2),
102            "test_unlocked3" => Ok(DifLcCtrlState::TestUnlocked3),
103            "test_locked3" => Ok(DifLcCtrlState::TestLocked3),
104            "test_unlocked4" => Ok(DifLcCtrlState::TestUnlocked4),
105            "test_locked4" => Ok(DifLcCtrlState::TestLocked4),
106            "test_unlocked5" => Ok(DifLcCtrlState::TestUnlocked5),
107            "test_locked5" => Ok(DifLcCtrlState::TestLocked5),
108            "test_unlocked6" => Ok(DifLcCtrlState::TestUnlocked6),
109            "test_locked6" => Ok(DifLcCtrlState::TestLocked6),
110            "test_unlocked7" => Ok(DifLcCtrlState::TestUnlocked7),
111            "dev" => Ok(DifLcCtrlState::Dev),
112            "prod" => Ok(DifLcCtrlState::Prod),
113            "prod_end" => Ok(DifLcCtrlState::ProdEnd),
114            "rma" => Ok(DifLcCtrlState::Rma),
115            "scrap" => Ok(DifLcCtrlState::Scrap),
116            "post_transition" => Ok(DifLcCtrlState::PostTransition),
117            "escalate" => Ok(DifLcCtrlState::Escalate),
118            _ => Ok(DifLcCtrlState::StateInvalid),
119        }
120    }
121
122    /// Checks whether a transition is valid and whether a non-zero token is
123    /// required.
124    pub fn check_transition(self, target: DifLcCtrlState) -> DifLcCtrlTransCheck {
125        match (self, target) {
126            // Transitions that require a token.
127            (DifLcCtrlState::Raw, DifLcCtrlState::TestUnlocked0)
128            | (DifLcCtrlState::Raw, DifLcCtrlState::TestUnlocked1)
129            | (DifLcCtrlState::Raw, DifLcCtrlState::TestUnlocked2)
130            | (DifLcCtrlState::Raw, DifLcCtrlState::TestUnlocked3)
131            | (DifLcCtrlState::Raw, DifLcCtrlState::TestUnlocked4)
132            | (DifLcCtrlState::Raw, DifLcCtrlState::TestUnlocked5)
133            | (DifLcCtrlState::Raw, DifLcCtrlState::TestUnlocked6)
134            | (DifLcCtrlState::Raw, DifLcCtrlState::TestUnlocked7)
135            | (DifLcCtrlState::TestUnlocked0, DifLcCtrlState::Dev)
136            | (DifLcCtrlState::TestUnlocked0, DifLcCtrlState::Prod)
137            | (DifLcCtrlState::TestUnlocked0, DifLcCtrlState::ProdEnd)
138            | (DifLcCtrlState::TestUnlocked1, DifLcCtrlState::Dev)
139            | (DifLcCtrlState::TestUnlocked1, DifLcCtrlState::Prod)
140            | (DifLcCtrlState::TestUnlocked1, DifLcCtrlState::ProdEnd)
141            | (DifLcCtrlState::TestUnlocked2, DifLcCtrlState::Dev)
142            | (DifLcCtrlState::TestUnlocked2, DifLcCtrlState::Prod)
143            | (DifLcCtrlState::TestUnlocked2, DifLcCtrlState::ProdEnd)
144            | (DifLcCtrlState::TestUnlocked3, DifLcCtrlState::Dev)
145            | (DifLcCtrlState::TestUnlocked3, DifLcCtrlState::Prod)
146            | (DifLcCtrlState::TestUnlocked3, DifLcCtrlState::ProdEnd)
147            | (DifLcCtrlState::TestUnlocked4, DifLcCtrlState::Dev)
148            | (DifLcCtrlState::TestUnlocked4, DifLcCtrlState::Prod)
149            | (DifLcCtrlState::TestUnlocked4, DifLcCtrlState::ProdEnd)
150            | (DifLcCtrlState::TestUnlocked5, DifLcCtrlState::Dev)
151            | (DifLcCtrlState::TestUnlocked5, DifLcCtrlState::Prod)
152            | (DifLcCtrlState::TestUnlocked5, DifLcCtrlState::ProdEnd)
153            | (DifLcCtrlState::TestUnlocked6, DifLcCtrlState::Dev)
154            | (DifLcCtrlState::TestUnlocked6, DifLcCtrlState::Prod)
155            | (DifLcCtrlState::TestUnlocked6, DifLcCtrlState::ProdEnd)
156            | (DifLcCtrlState::TestUnlocked7, DifLcCtrlState::Dev)
157            | (DifLcCtrlState::TestUnlocked7, DifLcCtrlState::Prod)
158            | (DifLcCtrlState::TestUnlocked7, DifLcCtrlState::ProdEnd)
159            | (DifLcCtrlState::TestLocked0, DifLcCtrlState::TestUnlocked1)
160            | (DifLcCtrlState::TestLocked0, DifLcCtrlState::TestUnlocked2)
161            | (DifLcCtrlState::TestLocked0, DifLcCtrlState::TestUnlocked3)
162            | (DifLcCtrlState::TestLocked0, DifLcCtrlState::TestUnlocked4)
163            | (DifLcCtrlState::TestLocked0, DifLcCtrlState::TestUnlocked5)
164            | (DifLcCtrlState::TestLocked0, DifLcCtrlState::TestUnlocked6)
165            | (DifLcCtrlState::TestLocked0, DifLcCtrlState::TestUnlocked7)
166            | (DifLcCtrlState::TestLocked0, DifLcCtrlState::Dev)
167            | (DifLcCtrlState::TestLocked0, DifLcCtrlState::Prod)
168            | (DifLcCtrlState::TestLocked0, DifLcCtrlState::ProdEnd)
169            | (DifLcCtrlState::TestLocked1, DifLcCtrlState::TestUnlocked2)
170            | (DifLcCtrlState::TestLocked1, DifLcCtrlState::TestUnlocked3)
171            | (DifLcCtrlState::TestLocked1, DifLcCtrlState::TestUnlocked4)
172            | (DifLcCtrlState::TestLocked1, DifLcCtrlState::TestUnlocked5)
173            | (DifLcCtrlState::TestLocked1, DifLcCtrlState::TestUnlocked6)
174            | (DifLcCtrlState::TestLocked1, DifLcCtrlState::TestUnlocked7)
175            | (DifLcCtrlState::TestLocked1, DifLcCtrlState::Dev)
176            | (DifLcCtrlState::TestLocked1, DifLcCtrlState::Prod)
177            | (DifLcCtrlState::TestLocked1, DifLcCtrlState::ProdEnd)
178            | (DifLcCtrlState::TestLocked2, DifLcCtrlState::TestUnlocked3)
179            | (DifLcCtrlState::TestLocked2, DifLcCtrlState::TestUnlocked4)
180            | (DifLcCtrlState::TestLocked2, DifLcCtrlState::TestUnlocked5)
181            | (DifLcCtrlState::TestLocked2, DifLcCtrlState::TestUnlocked6)
182            | (DifLcCtrlState::TestLocked2, DifLcCtrlState::TestUnlocked7)
183            | (DifLcCtrlState::TestLocked2, DifLcCtrlState::Dev)
184            | (DifLcCtrlState::TestLocked2, DifLcCtrlState::Prod)
185            | (DifLcCtrlState::TestLocked2, DifLcCtrlState::ProdEnd)
186            | (DifLcCtrlState::TestLocked3, DifLcCtrlState::TestUnlocked4)
187            | (DifLcCtrlState::TestLocked3, DifLcCtrlState::TestUnlocked5)
188            | (DifLcCtrlState::TestLocked3, DifLcCtrlState::TestUnlocked6)
189            | (DifLcCtrlState::TestLocked3, DifLcCtrlState::TestUnlocked7)
190            | (DifLcCtrlState::TestLocked3, DifLcCtrlState::Dev)
191            | (DifLcCtrlState::TestLocked3, DifLcCtrlState::Prod)
192            | (DifLcCtrlState::TestLocked3, DifLcCtrlState::ProdEnd)
193            | (DifLcCtrlState::TestLocked4, DifLcCtrlState::TestUnlocked5)
194            | (DifLcCtrlState::TestLocked4, DifLcCtrlState::TestUnlocked6)
195            | (DifLcCtrlState::TestLocked4, DifLcCtrlState::TestUnlocked7)
196            | (DifLcCtrlState::TestLocked4, DifLcCtrlState::Dev)
197            | (DifLcCtrlState::TestLocked4, DifLcCtrlState::Prod)
198            | (DifLcCtrlState::TestLocked4, DifLcCtrlState::ProdEnd)
199            | (DifLcCtrlState::TestLocked5, DifLcCtrlState::TestUnlocked6)
200            | (DifLcCtrlState::TestLocked5, DifLcCtrlState::TestUnlocked7)
201            | (DifLcCtrlState::TestLocked5, DifLcCtrlState::Dev)
202            | (DifLcCtrlState::TestLocked5, DifLcCtrlState::Prod)
203            | (DifLcCtrlState::TestLocked5, DifLcCtrlState::ProdEnd)
204            | (DifLcCtrlState::TestLocked6, DifLcCtrlState::TestUnlocked7)
205            | (DifLcCtrlState::TestLocked6, DifLcCtrlState::Dev)
206            | (DifLcCtrlState::TestLocked6, DifLcCtrlState::Prod)
207            | (DifLcCtrlState::TestLocked6, DifLcCtrlState::ProdEnd)
208            | (DifLcCtrlState::Dev, DifLcCtrlState::Rma)
209            | (DifLcCtrlState::Prod, DifLcCtrlState::Rma) => DifLcCtrlTransCheck {
210                valid: true,
211                token: true,
212            },
213            // Transitions that do not require a token.
214            (DifLcCtrlState::TestUnlocked0, DifLcCtrlState::Rma)
215            | (DifLcCtrlState::TestUnlocked1, DifLcCtrlState::Rma)
216            | (DifLcCtrlState::TestUnlocked2, DifLcCtrlState::Rma)
217            | (DifLcCtrlState::TestUnlocked3, DifLcCtrlState::Rma)
218            | (DifLcCtrlState::TestUnlocked4, DifLcCtrlState::Rma)
219            | (DifLcCtrlState::TestUnlocked5, DifLcCtrlState::Rma)
220            | (DifLcCtrlState::TestUnlocked6, DifLcCtrlState::Rma)
221            | (DifLcCtrlState::TestUnlocked7, DifLcCtrlState::Rma)
222            | (DifLcCtrlState::Raw, DifLcCtrlState::Scrap)
223            | (DifLcCtrlState::TestUnlocked0, DifLcCtrlState::Scrap)
224            | (DifLcCtrlState::TestUnlocked1, DifLcCtrlState::Scrap)
225            | (DifLcCtrlState::TestUnlocked2, DifLcCtrlState::Scrap)
226            | (DifLcCtrlState::TestUnlocked3, DifLcCtrlState::Scrap)
227            | (DifLcCtrlState::TestUnlocked4, DifLcCtrlState::Scrap)
228            | (DifLcCtrlState::TestUnlocked5, DifLcCtrlState::Scrap)
229            | (DifLcCtrlState::TestUnlocked6, DifLcCtrlState::Scrap)
230            | (DifLcCtrlState::TestUnlocked7, DifLcCtrlState::Scrap)
231            | (DifLcCtrlState::TestLocked0, DifLcCtrlState::Scrap)
232            | (DifLcCtrlState::TestLocked1, DifLcCtrlState::Scrap)
233            | (DifLcCtrlState::TestLocked2, DifLcCtrlState::Scrap)
234            | (DifLcCtrlState::TestLocked3, DifLcCtrlState::Scrap)
235            | (DifLcCtrlState::TestLocked4, DifLcCtrlState::Scrap)
236            | (DifLcCtrlState::TestLocked5, DifLcCtrlState::Scrap)
237            | (DifLcCtrlState::TestLocked6, DifLcCtrlState::Scrap)
238            | (DifLcCtrlState::Dev, DifLcCtrlState::Scrap)
239            | (DifLcCtrlState::Prod, DifLcCtrlState::Scrap)
240            | (DifLcCtrlState::ProdEnd, DifLcCtrlState::Scrap)
241            | (DifLcCtrlState::Rma, DifLcCtrlState::Scrap)
242            | (DifLcCtrlState::TestUnlocked0, DifLcCtrlState::TestLocked0)
243            | (DifLcCtrlState::TestUnlocked0, DifLcCtrlState::TestLocked1)
244            | (DifLcCtrlState::TestUnlocked0, DifLcCtrlState::TestLocked2)
245            | (DifLcCtrlState::TestUnlocked0, DifLcCtrlState::TestLocked3)
246            | (DifLcCtrlState::TestUnlocked0, DifLcCtrlState::TestLocked4)
247            | (DifLcCtrlState::TestUnlocked0, DifLcCtrlState::TestLocked5)
248            | (DifLcCtrlState::TestUnlocked0, DifLcCtrlState::TestLocked6)
249            | (DifLcCtrlState::TestUnlocked1, DifLcCtrlState::TestLocked1)
250            | (DifLcCtrlState::TestUnlocked1, DifLcCtrlState::TestLocked2)
251            | (DifLcCtrlState::TestUnlocked1, DifLcCtrlState::TestLocked3)
252            | (DifLcCtrlState::TestUnlocked1, DifLcCtrlState::TestLocked4)
253            | (DifLcCtrlState::TestUnlocked1, DifLcCtrlState::TestLocked5)
254            | (DifLcCtrlState::TestUnlocked1, DifLcCtrlState::TestLocked6)
255            | (DifLcCtrlState::TestUnlocked2, DifLcCtrlState::TestLocked2)
256            | (DifLcCtrlState::TestUnlocked2, DifLcCtrlState::TestLocked3)
257            | (DifLcCtrlState::TestUnlocked2, DifLcCtrlState::TestLocked4)
258            | (DifLcCtrlState::TestUnlocked2, DifLcCtrlState::TestLocked5)
259            | (DifLcCtrlState::TestUnlocked2, DifLcCtrlState::TestLocked6)
260            | (DifLcCtrlState::TestUnlocked3, DifLcCtrlState::TestLocked3)
261            | (DifLcCtrlState::TestUnlocked3, DifLcCtrlState::TestLocked4)
262            | (DifLcCtrlState::TestUnlocked3, DifLcCtrlState::TestLocked5)
263            | (DifLcCtrlState::TestUnlocked3, DifLcCtrlState::TestLocked6)
264            | (DifLcCtrlState::TestUnlocked4, DifLcCtrlState::TestLocked4)
265            | (DifLcCtrlState::TestUnlocked4, DifLcCtrlState::TestLocked5)
266            | (DifLcCtrlState::TestUnlocked4, DifLcCtrlState::TestLocked6)
267            | (DifLcCtrlState::TestUnlocked5, DifLcCtrlState::TestLocked5)
268            | (DifLcCtrlState::TestUnlocked5, DifLcCtrlState::TestLocked6)
269            | (DifLcCtrlState::TestUnlocked6, DifLcCtrlState::TestLocked6) => DifLcCtrlTransCheck {
270                valid: true,
271                token: false,
272            },
273            // Other transitions are invalid.
274            _ => DifLcCtrlTransCheck {
275                valid: false,
276                token: false,
277            },
278        }
279    }
280}
281
282#[derive(Copy, Clone)]
283pub struct DifLcCtrlToken(bindgen::dif::dif_lc_ctrl_token);
284
285impl From<[u8; 16]> for DifLcCtrlToken {
286    fn from(bytes: [u8; 16]) -> Self {
287        DifLcCtrlToken(bindgen::dif::dif_lc_ctrl_token { data: bytes })
288    }
289}
290
291impl From<Vec<u8>> for DifLcCtrlToken {
292    fn from(vector: Vec<u8>) -> Self {
293        let bytes: [u8; 16] = vector.try_into().unwrap();
294        DifLcCtrlToken::from(bytes)
295    }
296}
297
298impl From<[u32; 4]> for DifLcCtrlToken {
299    fn from(words: [u32; 4]) -> Self {
300        let bytes: [u8; 16] = words
301            .iter()
302            .flat_map(|v| v.to_le_bytes())
303            .collect::<Vec<u8>>()
304            .try_into()
305            .unwrap();
306        DifLcCtrlToken::from(bytes)
307    }
308}
309
310impl From<Vec<u32>> for DifLcCtrlToken {
311    fn from(vector: Vec<u32>) -> Self {
312        let bytes: [u8; 16] = vector
313            .iter()
314            .flat_map(|v| v.to_le_bytes())
315            .collect::<Vec<u8>>()
316            .try_into()
317            .unwrap();
318        DifLcCtrlToken::from(bytes)
319    }
320}
321
322impl DifLcCtrlToken {
323    /// Converts a 128-bit transition token into four native u32 words. These
324    /// values are suitable to write to [LcCtrlReg::TransitionToken0] and
325    /// friends.
326    pub fn into_register_values(self) -> [u32; 4] {
327        let mut out_words = [0u32; 4];
328        let bytes = self.0.data;
329        bytes
330            .chunks_exact(std::mem::size_of::<u32>())
331            .map(|chunk| u32::from_le_bytes(chunk.try_into().unwrap()))
332            .zip(&mut out_words)
333            .for_each(|(word, out)| *out = word);
334        out_words
335    }
336
337    /// Returns true if the token is zero.
338    pub fn is_zero(self) -> bool {
339        self.0.data == [0; 16]
340    }
341}
342
343#[derive(clap::ValueEnum, Clone, Copy, Debug, strum::EnumString)]
344#[strum(serialize_all = "snake_case")]
345#[repr(u32)]
346pub enum LcCtrlReg {
347    AlertTest = bindgen::dif::LC_CTRL_ALERT_TEST_REG_OFFSET,
348    Status = bindgen::dif::LC_CTRL_STATUS_REG_OFFSET,
349    ClaimTransitionIf = bindgen::dif::LC_CTRL_CLAIM_TRANSITION_IF_REG_OFFSET,
350    TransitionRegwen = bindgen::dif::LC_CTRL_TRANSITION_REGWEN_REG_OFFSET,
351    TransitionCmd = bindgen::dif::LC_CTRL_TRANSITION_CMD_REG_OFFSET,
352    TransitionCtrl = bindgen::dif::LC_CTRL_TRANSITION_CTRL_REG_OFFSET,
353    TransitionToken0 = bindgen::dif::LC_CTRL_TRANSITION_TOKEN_0_REG_OFFSET,
354    TransitionToken1 = bindgen::dif::LC_CTRL_TRANSITION_TOKEN_1_REG_OFFSET,
355    TransitionToken2 = bindgen::dif::LC_CTRL_TRANSITION_TOKEN_2_REG_OFFSET,
356    TransitionToken3 = bindgen::dif::LC_CTRL_TRANSITION_TOKEN_3_REG_OFFSET,
357    TransitionTarget = bindgen::dif::LC_CTRL_TRANSITION_TARGET_REG_OFFSET,
358    OtpVendorTestCtrl = bindgen::dif::LC_CTRL_OTP_VENDOR_TEST_CTRL_REG_OFFSET,
359    OtpVendorTestStatus = bindgen::dif::LC_CTRL_OTP_VENDOR_TEST_STATUS_REG_OFFSET,
360    LcState = bindgen::dif::LC_CTRL_LC_STATE_REG_OFFSET,
361    LcTransitionCnt = bindgen::dif::LC_CTRL_LC_TRANSITION_CNT_REG_OFFSET,
362    LcIdState = bindgen::dif::LC_CTRL_LC_ID_STATE_REG_OFFSET,
363    HwRevision0 = bindgen::dif::LC_CTRL_HW_REVISION0_REG_OFFSET,
364    HwRevision1 = bindgen::dif::LC_CTRL_HW_REVISION1_REG_OFFSET,
365    DeviceId0 = bindgen::dif::LC_CTRL_DEVICE_ID_0_REG_OFFSET,
366    DeviceId1 = bindgen::dif::LC_CTRL_DEVICE_ID_1_REG_OFFSET,
367    DeviceId2 = bindgen::dif::LC_CTRL_DEVICE_ID_2_REG_OFFSET,
368    DeviceId3 = bindgen::dif::LC_CTRL_DEVICE_ID_3_REG_OFFSET,
369    DeviceId4 = bindgen::dif::LC_CTRL_DEVICE_ID_4_REG_OFFSET,
370    DeviceId5 = bindgen::dif::LC_CTRL_DEVICE_ID_5_REG_OFFSET,
371    DeviceId6 = bindgen::dif::LC_CTRL_DEVICE_ID_6_REG_OFFSET,
372    DeviceId7 = bindgen::dif::LC_CTRL_DEVICE_ID_7_REG_OFFSET,
373    ManufState0 = bindgen::dif::LC_CTRL_MANUF_STATE_0_REG_OFFSET,
374    ManufState1 = bindgen::dif::LC_CTRL_MANUF_STATE_1_REG_OFFSET,
375    ManufState2 = bindgen::dif::LC_CTRL_MANUF_STATE_2_REG_OFFSET,
376    ManufState3 = bindgen::dif::LC_CTRL_MANUF_STATE_3_REG_OFFSET,
377    ManufState4 = bindgen::dif::LC_CTRL_MANUF_STATE_4_REG_OFFSET,
378    ManufState5 = bindgen::dif::LC_CTRL_MANUF_STATE_5_REG_OFFSET,
379    ManufState6 = bindgen::dif::LC_CTRL_MANUF_STATE_6_REG_OFFSET,
380    ManufState7 = bindgen::dif::LC_CTRL_MANUF_STATE_7_REG_OFFSET,
381}
382
383impl LcCtrlReg {
384    pub fn byte_offset(&self) -> u32 {
385        *self as u32
386    }
387    /// Converts the register's byte offset into a word offset for use with DMI.
388    /// <https://opentitan.org/book/hw/ip/lc_ctrl/doc/theory_of_operation.html#life-cycle-tap-controller>
389    pub fn word_offset(&self) -> u32 {
390        const BYTES_PER_WORD: u32 = std::mem::size_of::<u32>() as u32;
391        assert_eq!(self.byte_offset() % BYTES_PER_WORD, 0);
392        self.byte_offset() / BYTES_PER_WORD
393    }
394}
395
396bitflags! {
397    /// Bits of the lc_ctrl.STATUS register, aka [LcCtrlReg::Status].
398    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
399    #[serde(transparent)]
400    pub struct LcCtrlStatus: u32 {
401        const INITIALIZED            = 0b1 << bindgen::dif::LC_CTRL_STATUS_INITIALIZED_BIT;
402        const READY                  = 0b1 << bindgen::dif::LC_CTRL_STATUS_READY_BIT;
403        const EXT_CLOCK_SWITCHED     = 0b1 << bindgen::dif::LC_CTRL_STATUS_EXT_CLOCK_SWITCHED_BIT;
404        const TRANSITION_SUCCESSFUL  = 0b1 << bindgen::dif::LC_CTRL_STATUS_TRANSITION_SUCCESSFUL_BIT;
405        const TRANSITION_COUNT_ERROR = 0b1 << bindgen::dif::LC_CTRL_STATUS_TRANSITION_COUNT_ERROR_BIT;
406        const TRANSITION_ERROR       = 0b1 << bindgen::dif::LC_CTRL_STATUS_TRANSITION_ERROR_BIT;
407        const TOKEN_ERROR            = 0b1 << bindgen::dif::LC_CTRL_STATUS_TOKEN_ERROR_BIT;
408        const FLASH_RMA_ERROR        = 0b1 << bindgen::dif::LC_CTRL_STATUS_FLASH_RMA_ERROR_BIT;
409        const OTP_ERROR              = 0b1 << bindgen::dif::LC_CTRL_STATUS_OTP_ERROR_BIT;
410        const STATE_ERROR            = 0b1 << bindgen::dif::LC_CTRL_STATUS_STATE_ERROR_BIT;
411        const BUS_INTEG_ERROR        = 0b1 << bindgen::dif::LC_CTRL_STATUS_BUS_INTEG_ERROR_BIT;
412        const OTP_PARTITION_ERROR    = 0b1 << bindgen::dif::LC_CTRL_STATUS_OTP_PARTITION_ERROR_BIT;
413
414        const ERRORS =
415            Self::TRANSITION_COUNT_ERROR.bits() |
416            Self::TRANSITION_ERROR.bits() |
417            Self::TOKEN_ERROR.bits() |
418            Self::FLASH_RMA_ERROR.bits() |
419            Self::OTP_ERROR.bits() |
420            Self::STATE_ERROR.bits() |
421            Self::BUS_INTEG_ERROR.bits() |
422            Self::OTP_PARTITION_ERROR.bits();
423    }
424}
425
426bitflags! {
427    /// Bits of the lc_ctrl.TRANSITION_REGWEN register, aka [LcCtrlReg::TransitionRegwen].
428    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
429    pub struct LcCtrlTransitionRegwen: u32 {
430        const TRANSITION_REGWEN = 0b1 << bindgen::dif::LC_CTRL_TRANSITION_REGWEN_TRANSITION_REGWEN_BIT;
431    }
432}
433
434bitflags! {
435    /// Bits of the lc_ctrl.TRANSITION_CMD register, aka [LcCtrlReg::TransitionCmd].
436    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
437    pub struct LcCtrlTransitionCmd: u32 {
438        const START = 0b1 << bindgen::dif::LC_CTRL_TRANSITION_CMD_START_BIT;
439    }
440}
441
442bitflags! {
443    /// Bits of the lc_ctrl.TRANSITION_CTRL register, aka [LcCtrlReg::TransitionCtrl].
444    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
445    pub struct LcCtrlTransitionCtrl: u32 {
446        const EXT_CLOCK_EN = 0b1 << bindgen::dif::LC_CTRL_TRANSITION_CTRL_EXT_CLOCK_EN_BIT;
447        const VOLATILE_RAW_UNLOCK = 0b1 << bindgen::dif::LC_CTRL_TRANSITION_CTRL_VOLATILE_RAW_UNLOCK_BIT;
448    }
449}
450
451#[cfg(test)]
452mod tests {
453    use super::*;
454
455    /// Raw is zero, so its redundant encoding is a fixed point.
456    #[test]
457    fn lc_ctrl_state_redundant_encoding_zero() {
458        assert_eq!(u32::from(DifLcCtrlState::Raw), 0);
459        assert_eq!(DifLcCtrlState::Raw.redundant_encoding(), 0);
460    }
461
462    /// The redundant encoding of non-zero values shouldn't be a fixed point.
463    #[test]
464    fn lc_ctrl_state_redundant_encoding_nonzero() {
465        assert_ne!(
466            u32::from(DifLcCtrlState::Rma),
467            DifLcCtrlState::Rma.redundant_encoding()
468        );
469        assert_eq!(DifLcCtrlState::Rma.redundant_encoding(), 0x2739ce73);
470    }
471
472    #[test]
473    fn lc_ctrl_token() {
474        // This test assumes the system is little-endian.
475        let token_bytes: [u8; 16] = [
476            0x01, 0x02, 0x03, 0x04, // TOKEN_0
477            0x11, 0x12, 0x13, 0x14, // TOKEN_1
478            0x21, 0x22, 0x23, 0x24, // TOKEN_2
479            0x31, 0x32, 0x33, 0x34, // TOKEN_3
480        ];
481        let token = DifLcCtrlToken::from(token_bytes);
482        let words: [u32; 4] = token.into_register_values();
483        assert_eq!(words, [0x04030201, 0x14131211, 0x24232221, 0x34333231]);
484    }
485
486    #[test]
487    fn lc_ctrl_register_offsets() {
488        let offset = bindgen::dif::LC_CTRL_LC_STATE_REG_OFFSET;
489        assert_eq!(LcCtrlReg::LcState.byte_offset(), offset);
490        assert_eq!(LcCtrlReg::LcState.word_offset(), offset / 4);
491    }
492
493    #[test]
494    fn lc_status_bits() {
495        assert_eq!(LcCtrlStatus::empty(), LcCtrlStatus::from_bits_truncate(0));
496        assert_eq!(
497            LcCtrlStatus::INITIALIZED,
498            LcCtrlStatus::from_bits_truncate(1)
499        );
500        assert_eq!(
501            LcCtrlStatus::INITIALIZED | LcCtrlStatus::READY,
502            LcCtrlStatus::from_bits_truncate(3)
503        );
504
505        let ready = LcCtrlStatus::INITIALIZED | LcCtrlStatus::READY;
506        assert!(ready.contains(LcCtrlStatus::READY));
507        assert!(!ready.contains(LcCtrlStatus::TRANSITION_SUCCESSFUL));
508    }
509}