Software APIs
otp.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 "sw/device/silicon_creator/lib/drivers/otp.h"
6 
7 #include <stddef.h>
8 
13 #include "sw/device/silicon_creator/lib/error.h"
14 
16 #include "otp_ctrl_regs.h" // Generated.
17 
18 enum {
20 };
21 
22 // This is generates too many lines with different formatting variants, so
23 // We opt to just disable formatting.
24 // clang-format off
25 const otp_partition_info_t kOtpPartitions[] = {
26  [kOtpPartitionCreatorSwCfg] = {
27  .start_addr = OTP_CTRL_PARAM_CREATOR_SW_CFG_OFFSET,
28  .size = OTP_CTRL_PARAM_CREATOR_SW_CFG_SIZE -
29  OTP_CTRL_PARAM_CREATOR_SW_CFG_DIGEST_SIZE,
30  .digest_addr = OTP_CTRL_CREATOR_SW_CFG_DIGEST_0_REG_OFFSET,
31  .align_mask = 0x3},
32  [kOtpPartitionOwnerSwCfg] = {
33  .start_addr = OTP_CTRL_PARAM_OWNER_SW_CFG_OFFSET,
34  .size = OTP_CTRL_PARAM_OWNER_SW_CFG_SIZE -
35  OTP_CTRL_PARAM_OWNER_SW_CFG_DIGEST_SIZE,
36  .digest_addr = OTP_CTRL_OWNER_SW_CFG_DIGEST_0_REG_OFFSET,
37  .align_mask = 0x3},
38  [kOtpPartitionRotCreatorAuthCodesign] = {
39  .start_addr = OTP_CTRL_PARAM_ROT_CREATOR_AUTH_CODESIGN_OFFSET,
40  .size = OTP_CTRL_PARAM_ROT_CREATOR_AUTH_CODESIGN_SIZE -
41  OTP_CTRL_PARAM_ROT_CREATOR_AUTH_CODESIGN_DIGEST_SIZE,
42  .digest_addr = OTP_CTRL_ROT_CREATOR_AUTH_CODESIGN_DIGEST_0_REG_OFFSET,
43  .align_mask = 0x3},
44  [kOtpPartitionRotCreatorAuthState] = {
45  .start_addr = OTP_CTRL_PARAM_ROT_CREATOR_AUTH_STATE_OFFSET,
46  .size = OTP_CTRL_PARAM_ROT_CREATOR_AUTH_STATE_SIZE -
47  OTP_CTRL_PARAM_ROT_CREATOR_AUTH_STATE_DIGEST_SIZE,
48  .digest_addr = OTP_CTRL_ROT_CREATOR_AUTH_STATE_DIGEST_0_REG_OFFSET,
49  .align_mask = 0x3},
50  [kOtpPartitionHwCfg0] = {
51  .start_addr = OTP_CTRL_PARAM_HW_CFG0_OFFSET,
52  .size = OTP_CTRL_PARAM_HW_CFG0_SIZE -
53  OTP_CTRL_PARAM_HW_CFG0_DIGEST_SIZE,
54  .digest_addr = OTP_CTRL_HW_CFG0_DIGEST_0_REG_OFFSET,
55  .align_mask = 0x3},
56  [kOtpPartitionHwCfg1] = {
57  .start_addr = OTP_CTRL_PARAM_HW_CFG1_OFFSET,
58  .size = OTP_CTRL_PARAM_HW_CFG1_SIZE -
59  OTP_CTRL_PARAM_HW_CFG1_DIGEST_SIZE,
60  .digest_addr = OTP_CTRL_HW_CFG1_DIGEST_0_REG_OFFSET,
61  .align_mask = 0x3},
62 };
63 // clang-format on
64 
65 uint32_t otp_read32(uint32_t address) {
66  return sec_mmio_read32(kBase + OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET + address);
67 }
68 
69 uint64_t otp_read64(uint32_t address) {
70  uint32_t reg_offset = OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET + address;
71  uint64_t value = sec_mmio_read32(kBase + reg_offset + sizeof(uint32_t));
72  value <<= 32;
73  value |= sec_mmio_read32(kBase + reg_offset);
74 
75  return value;
76 }
77 
78 void otp_read(uint32_t address, uint32_t *data, size_t num_words) {
79  uint32_t reg_offset = OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET + address;
80  size_t i = 0, r = num_words - 1;
81  for (; launder32(i) < num_words && launder32(r) < num_words; ++i, --r) {
82  data[i] = sec_mmio_read32(kBase + reg_offset + i * sizeof(uint32_t));
83  }
84  HARDENED_CHECK_EQ(i, num_words);
85  HARDENED_CHECK_EQ(r, SIZE_MAX);
86 }
87 
88 uint64_t otp_partition_digest_read(otp_partition_t partition) {
89  uint32_t reg_offset = kBase + kOtpPartitions[partition].digest_addr;
90  uint64_t value = sec_mmio_read32(reg_offset + sizeof(uint32_t));
91  value <<= 32;
92  value |= sec_mmio_read32(reg_offset);
93  return value;
94 }
95 
96 static void wait_for_dai_idle(void) {
97  uint32_t status = 0;
98  bool idle = false;
99  do {
100  status = abs_mmio_read32(kBase + OTP_CTRL_STATUS_REG_OFFSET);
101  idle = bitfield_bit32_read(status, OTP_CTRL_STATUS_DAI_IDLE_BIT);
102  } while (!idle);
103 }
104 
105 static void dai_read_blocking(otp_partition_t partition,
106  uint32_t relative_address) {
107  wait_for_dai_idle();
108  HARDENED_CHECK_EQ(relative_address & kOtpPartitions[partition].align_mask, 0);
109  abs_mmio_write32(kBase + OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
110  kOtpPartitions[partition].start_addr + relative_address);
111  uint32_t cmd =
112  bitfield_bit32_write(0, OTP_CTRL_DIRECT_ACCESS_CMD_RD_BIT, true);
113  abs_mmio_write32(kBase + OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET, cmd);
114  wait_for_dai_idle();
115 }
116 
117 uint32_t otp_dai_read32(otp_partition_t partition, uint32_t relative_address) {
118  dai_read_blocking(partition, relative_address);
119  return abs_mmio_read32(kBase + OTP_CTRL_DIRECT_ACCESS_RDATA_0_REG_OFFSET);
120 }
121 
122 uint64_t otp_dai_read64(otp_partition_t partition, uint32_t relative_address) {
123  dai_read_blocking(partition, relative_address);
124  uint64_t value =
125  abs_mmio_read32(kBase + OTP_CTRL_DIRECT_ACCESS_RDATA_1_REG_OFFSET);
126  value <<= 32;
127  value |= abs_mmio_read32(kBase + OTP_CTRL_DIRECT_ACCESS_RDATA_0_REG_OFFSET);
128  return value;
129 }
130 
131 rom_error_t otp_dai_read(otp_partition_t partition, uint32_t relative_address,
132  uint32_t *data, size_t num_words) {
133  HARDENED_CHECK_LT(partition, ARRAYSIZE(kOtpPartitions));
134  size_t i = 0, r = num_words - 1;
135  uint32_t addr = relative_address;
136  for (; launder32(i) < num_words && launder32(r) < num_words; ++i, --r) {
137  data[i] = otp_dai_read32(partition, addr);
138  addr += sizeof(uint32_t);
139  }
140  HARDENED_CHECK_EQ(i, num_words);
141  HARDENED_CHECK_EQ(r, SIZE_MAX);
142  return kErrorOk;
143 }
144 
145 void otp_creator_sw_cfg_lockdown(void) {
146  SEC_MMIO_ASSERT_WRITE_INCREMENT(kOtpSecMmioCreatorSwCfgLockDown, 1);
147  sec_mmio_write32(kBase + OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_REG_OFFSET, 0);
148 }