opentitanlib/dif/
otp_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 std::collections::HashSet;
6use std::sync::LazyLock;
7
8use bindgen::dif;
9use bitflags::bitflags;
10
11use crate::collection;
12
13#[derive(Copy, Clone, Debug, PartialEq, Eq)]
14#[repr(u32)]
15#[non_exhaustive]
16pub enum OtpCtrlReg {
17    IntrState = dif::OTP_CTRL_INTR_STATE_REG_OFFSET,
18    IntrEnable = dif::OTP_CTRL_INTR_ENABLE_REG_OFFSET,
19    IntrTest = dif::OTP_CTRL_INTR_TEST_REG_OFFSET,
20    AlertTest = dif::OTP_CTRL_ALERT_TEST_REG_OFFSET,
21    Status = dif::OTP_CTRL_STATUS_REG_OFFSET,
22    ErrCode0 = dif::OTP_CTRL_ERR_CODE_0_REG_OFFSET,
23    ErrCode1 = dif::OTP_CTRL_ERR_CODE_1_REG_OFFSET,
24    ErrCode2 = dif::OTP_CTRL_ERR_CODE_2_REG_OFFSET,
25    ErrCode3 = dif::OTP_CTRL_ERR_CODE_3_REG_OFFSET,
26    ErrCode4 = dif::OTP_CTRL_ERR_CODE_4_REG_OFFSET,
27    ErrCode5 = dif::OTP_CTRL_ERR_CODE_5_REG_OFFSET,
28    ErrCode6 = dif::OTP_CTRL_ERR_CODE_6_REG_OFFSET,
29    ErrCode7 = dif::OTP_CTRL_ERR_CODE_7_REG_OFFSET,
30    ErrCode8 = dif::OTP_CTRL_ERR_CODE_8_REG_OFFSET,
31    ErrCode9 = dif::OTP_CTRL_ERR_CODE_9_REG_OFFSET,
32    DirectAccessRegwen = dif::OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
33    DirectAccessCmd = dif::OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
34    DirectAccessAddress = dif::OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
35    DirectAccessWdata0 = dif::OTP_CTRL_DIRECT_ACCESS_WDATA_0_REG_OFFSET,
36    DirectAccessWdata1 = dif::OTP_CTRL_DIRECT_ACCESS_WDATA_1_REG_OFFSET,
37    DirectAccessRdata0 = dif::OTP_CTRL_DIRECT_ACCESS_RDATA_0_REG_OFFSET,
38    DirectAccessRdata1 = dif::OTP_CTRL_DIRECT_ACCESS_RDATA_1_REG_OFFSET,
39    CheckTriggerRegwen = dif::OTP_CTRL_CHECK_TRIGGER_REGWEN_REG_OFFSET,
40    CheckTrigger = dif::OTP_CTRL_CHECK_TRIGGER_REG_OFFSET,
41    CheckRegwen = dif::OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
42    CheckTimeout = dif::OTP_CTRL_CHECK_TIMEOUT_REG_OFFSET,
43    IntegrityCheckPeriod = dif::OTP_CTRL_INTEGRITY_CHECK_PERIOD_REG_OFFSET,
44    ConsistencyCheckPeriod = dif::OTP_CTRL_CONSISTENCY_CHECK_PERIOD_REG_OFFSET,
45    VendorTestReadLock = dif::OTP_CTRL_VENDOR_TEST_READ_LOCK_REG_OFFSET,
46    CreatorSwCfgReadLock = dif::OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_REG_OFFSET,
47    OwnerSwCfgReadLock = dif::OTP_CTRL_OWNER_SW_CFG_READ_LOCK_REG_OFFSET,
48    VendorTestDigest0 = dif::OTP_CTRL_VENDOR_TEST_DIGEST_0_REG_OFFSET,
49    VendorTestDigest1 = dif::OTP_CTRL_VENDOR_TEST_DIGEST_1_REG_OFFSET,
50    CreatorSwCfgDigest0 = dif::OTP_CTRL_CREATOR_SW_CFG_DIGEST_0_REG_OFFSET,
51    CreatorSwCfgDigest1 = dif::OTP_CTRL_CREATOR_SW_CFG_DIGEST_1_REG_OFFSET,
52    OwnerSwCfgDigest0 = dif::OTP_CTRL_OWNER_SW_CFG_DIGEST_0_REG_OFFSET,
53    OwnerSwCfgDigest1 = dif::OTP_CTRL_OWNER_SW_CFG_DIGEST_1_REG_OFFSET,
54    HwCfgDigest0 = dif::OTP_CTRL_HW_CFG0_DIGEST_0_REG_OFFSET,
55    HwCfgDigest1 = dif::OTP_CTRL_HW_CFG0_DIGEST_1_REG_OFFSET,
56    Secret0Digest0 = dif::OTP_CTRL_SECRET0_DIGEST_0_REG_OFFSET,
57    Secret0Digest1 = dif::OTP_CTRL_SECRET0_DIGEST_1_REG_OFFSET,
58    Secret1Digest0 = dif::OTP_CTRL_SECRET1_DIGEST_0_REG_OFFSET,
59    Secret1Digest1 = dif::OTP_CTRL_SECRET1_DIGEST_1_REG_OFFSET,
60    Secret2Digest0 = dif::OTP_CTRL_SECRET2_DIGEST_0_REG_OFFSET,
61    Secret2Digest1 = dif::OTP_CTRL_SECRET2_DIGEST_1_REG_OFFSET,
62    SwCfgWindow = dif::OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET,
63}
64
65bitflags! {
66    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
67    pub struct DirectAccessCmd: u32 {
68        const DIGEST = 0b1 << dif::OTP_CTRL_DIRECT_ACCESS_CMD_DIGEST_BIT;
69        const RD     = 0b1 << dif::OTP_CTRL_DIRECT_ACCESS_CMD_RD_BIT;
70        const WR     = 0b1 << dif::OTP_CTRL_DIRECT_ACCESS_CMD_WR_BIT;
71    }
72}
73
74bitflags! {
75    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
76    pub struct OtpCtrlStatus: u32 {
77        const BUS_INTEG_ERROR       = 0b1 << dif::OTP_CTRL_STATUS_BUS_INTEG_ERROR_BIT;
78        const CHECK_PENDING         = 0b1 << dif::OTP_CTRL_STATUS_CHECK_PENDING_BIT;
79        const CREATOR_SW_CFG_ERROR  = 0b1 << dif::OTP_CTRL_STATUS_CREATOR_SW_CFG_ERROR_BIT;
80        const DAI_ERROR             = 0b1 << dif::OTP_CTRL_STATUS_DAI_ERROR_BIT;
81        const DAI_IDLE              = 0b1 << dif::OTP_CTRL_STATUS_DAI_IDLE_BIT;
82        const HW_CFG0_ERROR         = 0b1 << dif::OTP_CTRL_STATUS_HW_CFG0_ERROR_BIT;
83        const KEY_DERIV_FSM_ERROR   = 0b1 << dif::OTP_CTRL_STATUS_KEY_DERIV_FSM_ERROR_BIT;
84        const LCI_ERROR             = 0b1 << dif::OTP_CTRL_STATUS_LCI_ERROR_BIT;
85        const LFSR_FSM_ERROR        = 0b1 << dif::OTP_CTRL_STATUS_LFSR_FSM_ERROR_BIT;
86        const LIFE_CYCLE_ERROR      = 0b1 << dif::OTP_CTRL_STATUS_LIFE_CYCLE_ERROR_BIT;
87        const OWNER_SW_CFG_ERROR    = 0b1 << dif::OTP_CTRL_STATUS_OWNER_SW_CFG_ERROR_BIT;
88        const SCRAMBLING_FSM_ERROR  = 0b1 << dif::OTP_CTRL_STATUS_SCRAMBLING_FSM_ERROR_BIT;
89        const SECRET0_ERROR         = 0b1 << dif::OTP_CTRL_STATUS_SECRET0_ERROR_BIT;
90        const SECRET1_ERROR         = 0b1 << dif::OTP_CTRL_STATUS_SECRET1_ERROR_BIT;
91        const SECRET2_ERROR         = 0b1 << dif::OTP_CTRL_STATUS_SECRET2_ERROR_BIT;
92        const TIMEOUT_ERROR         = 0b1 << dif::OTP_CTRL_STATUS_TIMEOUT_ERROR_BIT;
93        const VENDOR_TEST_ERROR     = 0b1 << dif::OTP_CTRL_STATUS_VENDOR_TEST_ERROR_BIT;
94
95        const ERRORS =
96            Self::BUS_INTEG_ERROR.bits() |
97            Self::CREATOR_SW_CFG_ERROR.bits() |
98            Self::DAI_ERROR.bits() |
99            Self::HW_CFG0_ERROR.bits() |
100            Self::KEY_DERIV_FSM_ERROR.bits() |
101            Self::LCI_ERROR.bits() |
102            Self::LFSR_FSM_ERROR.bits() |
103            Self::LIFE_CYCLE_ERROR.bits() |
104            Self::OWNER_SW_CFG_ERROR.bits() |
105            Self::SCRAMBLING_FSM_ERROR.bits() |
106            Self::SECRET0_ERROR.bits() |
107            Self::SECRET1_ERROR.bits() |
108            Self::SECRET2_ERROR.bits() |
109            Self::TIMEOUT_ERROR.bits() |
110            Self::VENDOR_TEST_ERROR.bits();
111    }
112}
113
114#[derive(Clone, Eq, PartialEq, Hash)]
115pub struct Partition {
116    /// Granularity of accesses at this address.
117    pub access_granule: Granularity,
118
119    /// Starting address of this partition within the OTP in bytes.
120    pub byte_addr: u32,
121
122    /// Digest MMAP for this partition.
123    ///
124    /// Must be accessed with 64-bit granularity, regardless of this
125    /// partition's `access_granule`.
126    pub digest: OtpParamMmap,
127}
128
129impl Partition {
130    // TODO: Take granularities from the `.hjson` instead of hardcoding.
131    pub const CREATOR_SW_CFG: Self = Self {
132        access_granule: Granularity::B32,
133        byte_addr: dif::OTP_CTRL_PARAM_CREATOR_SW_CFG_OFFSET,
134        digest: OtpParamMmap {
135            byte_addr: dif::OTP_CTRL_PARAM_CREATOR_SW_CFG_DIGEST_OFFSET,
136            size: dif::OTP_CTRL_PARAM_CREATOR_SW_CFG_DIGEST_SIZE,
137        },
138    };
139
140    pub const OWNER_SW_CFG: Self = Self {
141        access_granule: Granularity::B32,
142        byte_addr: dif::OTP_CTRL_PARAM_OWNER_SW_CFG_OFFSET,
143        digest: OtpParamMmap {
144            byte_addr: dif::OTP_CTRL_PARAM_OWNER_SW_CFG_DIGEST_OFFSET,
145            size: dif::OTP_CTRL_PARAM_OWNER_SW_CFG_DIGEST_SIZE,
146        },
147    };
148
149    pub const HW_CFG0: Self = Self {
150        access_granule: Granularity::B32,
151        byte_addr: dif::OTP_CTRL_PARAM_HW_CFG0_OFFSET,
152        digest: OtpParamMmap {
153            byte_addr: dif::OTP_CTRL_PARAM_HW_CFG0_DIGEST_OFFSET,
154            size: dif::OTP_CTRL_PARAM_HW_CFG0_DIGEST_SIZE,
155        },
156    };
157
158    pub const SECRET0: Self = Self {
159        access_granule: Granularity::B64,
160        byte_addr: dif::OTP_CTRL_PARAM_SECRET0_OFFSET,
161        digest: OtpParamMmap {
162            byte_addr: dif::OTP_CTRL_PARAM_SECRET0_DIGEST_OFFSET,
163            size: dif::OTP_CTRL_PARAM_SECRET0_DIGEST_SIZE,
164        },
165    };
166
167    pub const SECRET1: Self = Self {
168        access_granule: Granularity::B64,
169        byte_addr: dif::OTP_CTRL_PARAM_SECRET1_OFFSET,
170        digest: OtpParamMmap {
171            byte_addr: dif::OTP_CTRL_PARAM_SECRET1_DIGEST_OFFSET,
172            size: dif::OTP_CTRL_PARAM_SECRET1_DIGEST_SIZE,
173        },
174    };
175
176    pub const SECRET2: Self = Self {
177        access_granule: Granularity::B64,
178        byte_addr: dif::OTP_CTRL_PARAM_SECRET2_OFFSET,
179        digest: OtpParamMmap {
180            byte_addr: dif::OTP_CTRL_PARAM_SECRET2_DIGEST_OFFSET,
181            size: dif::OTP_CTRL_PARAM_SECRET2_DIGEST_SIZE,
182        },
183    };
184}
185
186/// Set of partitions that are secret.
187///
188/// A secret partition is scrambled and not readable after it is locked.
189pub static SECRET_PARTITIONS: LazyLock<HashSet<Partition>> = LazyLock::new(|| {
190    collection! {
191        Partition::SECRET0, Partition::SECRET1, Partition::SECRET2,
192    }
193});
194
195/// Granularities of memory accesses.
196#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
197pub enum Granularity {
198    /// 32-bit.
199    B32,
200    /// 64-bit.
201    B64,
202}
203
204/// Represents an OTP parameter's mapping in the "direct access memory".
205#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
206pub struct OtpParamMmap {
207    /// Byte address of this OTP parameter.
208    pub byte_addr: u32,
209
210    /// Size in bytes.
211    pub size: u32,
212}
213
214/// Parameters accessible via Direct Access Interface (DAI).
215///
216/// Some fields in the `CREATOR_SW_CFG` and `OWNER_SW_CFG` partitions are omitted for brevity.
217#[derive(Clone, Copy, Debug, PartialEq, Eq)]
218pub enum DaiParam {
219    // CREATOR_SW_CFG
220    RomExecEn,
221    // OWNER_SW_CFG
222    RomBootstrapDis,
223    // HW_CFG
224    DeviceId,
225    ManufState,
226    EnSramIfetch,
227    EnCsrngSwAppRead,
228    // SECRET0
229    TestUnlockToken,
230    TestExitToken,
231    // SECRET1
232    FlashAddrKeySeed,
233    FlashDataKeySeed,
234    SramDataKeySeed,
235    // SECRET2
236    RmaToken,
237    CreatorRootKeyShare0,
238    CreatorRootKeyShare1,
239}
240
241impl DaiParam {
242    // These constants should be generated by `reggen` in the future.
243    pub const ROM_EXEC_EN: OtpParamMmap = OtpParamMmap {
244        byte_addr: dif::OTP_CTRL_PARAM_CREATOR_SW_CFG_ROM_EXEC_EN_OFFSET,
245        size: dif::OTP_CTRL_PARAM_CREATOR_SW_CFG_ROM_EXEC_EN_SIZE,
246    };
247    pub const ROM_BOOTSTRAP_DIS: OtpParamMmap = OtpParamMmap {
248        byte_addr: dif::OTP_CTRL_PARAM_OWNER_SW_CFG_ROM_BOOTSTRAP_DIS_OFFSET,
249        size: dif::OTP_CTRL_PARAM_OWNER_SW_CFG_ROM_BOOTSTRAP_DIS_SIZE,
250    };
251    pub const DEVICE_ID: OtpParamMmap = OtpParamMmap {
252        byte_addr: dif::OTP_CTRL_PARAM_DEVICE_ID_OFFSET,
253        size: dif::OTP_CTRL_PARAM_DEVICE_ID_SIZE,
254    };
255    pub const MANUF_STATE: OtpParamMmap = OtpParamMmap {
256        byte_addr: dif::OTP_CTRL_PARAM_MANUF_STATE_OFFSET,
257        size: dif::OTP_CTRL_PARAM_MANUF_STATE_SIZE,
258    };
259    pub const EN_SRAM_IFETCH: OtpParamMmap = OtpParamMmap {
260        byte_addr: dif::OTP_CTRL_PARAM_EN_SRAM_IFETCH_OFFSET,
261        size: dif::OTP_CTRL_PARAM_EN_SRAM_IFETCH_SIZE,
262    };
263    pub const EN_CSRNG_SW_APP_READ: OtpParamMmap = OtpParamMmap {
264        byte_addr: dif::OTP_CTRL_PARAM_EN_CSRNG_SW_APP_READ_OFFSET,
265        size: dif::OTP_CTRL_PARAM_EN_CSRNG_SW_APP_READ_SIZE,
266    };
267    pub const TEST_UNLOCK_TOKEN: OtpParamMmap = OtpParamMmap {
268        byte_addr: dif::OTP_CTRL_PARAM_TEST_UNLOCK_TOKEN_OFFSET,
269        size: dif::OTP_CTRL_PARAM_TEST_UNLOCK_TOKEN_SIZE,
270    };
271    pub const TEST_EXIT_TOKEN: OtpParamMmap = OtpParamMmap {
272        byte_addr: dif::OTP_CTRL_PARAM_TEST_EXIT_TOKEN_OFFSET,
273        size: dif::OTP_CTRL_PARAM_TEST_EXIT_TOKEN_SIZE,
274    };
275    pub const FLASH_ADDR_KEY_SEED: OtpParamMmap = OtpParamMmap {
276        byte_addr: dif::OTP_CTRL_PARAM_FLASH_ADDR_KEY_SEED_OFFSET,
277        size: dif::OTP_CTRL_PARAM_FLASH_ADDR_KEY_SEED_SIZE,
278    };
279    pub const FLASH_DATA_KEY_SEED: OtpParamMmap = OtpParamMmap {
280        byte_addr: dif::OTP_CTRL_PARAM_FLASH_DATA_KEY_SEED_OFFSET,
281        size: dif::OTP_CTRL_PARAM_FLASH_DATA_KEY_SEED_SIZE,
282    };
283    pub const SRAM_DATA_KEY_SEED: OtpParamMmap = OtpParamMmap {
284        byte_addr: dif::OTP_CTRL_PARAM_SRAM_DATA_KEY_SEED_OFFSET,
285        size: dif::OTP_CTRL_PARAM_SRAM_DATA_KEY_SEED_SIZE,
286    };
287    pub const RMA_TOKEN: OtpParamMmap = OtpParamMmap {
288        byte_addr: dif::OTP_CTRL_PARAM_RMA_TOKEN_OFFSET,
289        size: dif::OTP_CTRL_PARAM_RMA_TOKEN_SIZE,
290    };
291    pub const CREATOR_ROOT_KEY_SHARE0: OtpParamMmap = OtpParamMmap {
292        byte_addr: dif::OTP_CTRL_PARAM_CREATOR_ROOT_KEY_SHARE0_OFFSET,
293        size: dif::OTP_CTRL_PARAM_CREATOR_ROOT_KEY_SHARE0_SIZE,
294    };
295    pub const CREATOR_ROOT_KEY_SHARE1: OtpParamMmap = OtpParamMmap {
296        byte_addr: dif::OTP_CTRL_PARAM_CREATOR_ROOT_KEY_SHARE1_OFFSET,
297        size: dif::OTP_CTRL_PARAM_CREATOR_ROOT_KEY_SHARE1_SIZE,
298    };
299
300    /// Returns the mmap'd field of this DAI parameter.
301    pub const fn mmap(&self) -> OtpParamMmap {
302        match self {
303            Self::RomExecEn => Self::ROM_EXEC_EN,
304            Self::RomBootstrapDis => Self::ROM_BOOTSTRAP_DIS,
305            Self::DeviceId => Self::DEVICE_ID,
306            Self::ManufState => Self::MANUF_STATE,
307            Self::EnSramIfetch => Self::EN_SRAM_IFETCH,
308            Self::EnCsrngSwAppRead => Self::EN_CSRNG_SW_APP_READ,
309            Self::TestUnlockToken => Self::TEST_UNLOCK_TOKEN,
310            Self::TestExitToken => Self::TEST_EXIT_TOKEN,
311            Self::FlashAddrKeySeed => Self::FLASH_ADDR_KEY_SEED,
312            Self::FlashDataKeySeed => Self::FLASH_DATA_KEY_SEED,
313            Self::SramDataKeySeed => Self::SRAM_DATA_KEY_SEED,
314            Self::RmaToken => Self::RMA_TOKEN,
315            Self::CreatorRootKeyShare0 => Self::CREATOR_ROOT_KEY_SHARE0,
316            Self::CreatorRootKeyShare1 => Self::CREATOR_ROOT_KEY_SHARE1,
317        }
318    }
319
320    /// Returns the partition that this DAI parameter belongs to.
321    pub const fn partition(&self) -> Partition {
322        match self {
323            Self::RomExecEn => Partition::CREATOR_SW_CFG,
324            Self::RomBootstrapDis => Partition::OWNER_SW_CFG,
325            Self::DeviceId => Partition::HW_CFG0,
326            Self::ManufState => Partition::HW_CFG0,
327            Self::EnSramIfetch => Partition::HW_CFG0,
328            Self::EnCsrngSwAppRead => Partition::HW_CFG0,
329            Self::TestUnlockToken => Partition::SECRET0,
330            Self::TestExitToken => Partition::SECRET0,
331            Self::FlashAddrKeySeed => Partition::SECRET1,
332            Self::FlashDataKeySeed => Partition::SECRET1,
333            Self::SramDataKeySeed => Partition::SECRET1,
334            Self::RmaToken => Partition::SECRET2,
335            Self::CreatorRootKeyShare0 => Partition::SECRET2,
336            Self::CreatorRootKeyShare1 => Partition::SECRET2,
337        }
338    }
339}