Software APIs
dif_otp_ctrl.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
5 
6 #include <stddef.h>
7 
11 
12 #include "otp_ctrl_regs.h" // Generated.
13 
14 /**
15  * Checks if integrity/consistency-check-related operations are locked.
16  *
17  * This is a convenience function to avoid superfluous error-checking in all the
18  * functions that can be locked out by this register.
19  *
20  * @param check_config True to check the config regwen. False to check the
21  * trigger regwen.
22  */
23 static bool checks_are_locked(const dif_otp_ctrl_t *otp, bool check_config) {
24  ptrdiff_t reg_offset = check_config
25  ? OTP_CTRL_CHECK_REGWEN_REG_OFFSET
26  : OTP_CTRL_CHECK_TRIGGER_REGWEN_REG_OFFSET;
27  size_t regwen_bit =
28  check_config ? OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT
29  : OTP_CTRL_CHECK_TRIGGER_REGWEN_CHECK_TRIGGER_REGWEN_BIT;
30  uint32_t locked = mmio_region_read32(otp->base_addr, reg_offset);
31  return !bitfield_bit32_read(locked, regwen_bit);
32 }
33 
34 dif_result_t dif_otp_ctrl_configure(const dif_otp_ctrl_t *otp,
35  dif_otp_ctrl_config_t config) {
36  if (otp == NULL) {
37  return kDifBadArg;
38  }
39  if (checks_are_locked(otp, /*check_config=*/true)) {
40  return kDifLocked;
41  }
42 
43  mmio_region_write32(otp->base_addr, OTP_CTRL_CHECK_TIMEOUT_REG_OFFSET,
44  config.check_timeout);
45  mmio_region_write32(otp->base_addr,
46  OTP_CTRL_INTEGRITY_CHECK_PERIOD_REG_OFFSET,
47  config.integrity_period_mask);
48  mmio_region_write32(otp->base_addr,
49  OTP_CTRL_CONSISTENCY_CHECK_PERIOD_REG_OFFSET,
51 
52  return kDifOk;
53 }
54 
55 dif_result_t dif_otp_ctrl_check_integrity(const dif_otp_ctrl_t *otp) {
56  if (otp == NULL) {
57  return kDifBadArg;
58  }
59  if (checks_are_locked(otp, /*check_config=*/false)) {
60  return kDifLocked;
61  }
62 
63  uint32_t reg =
64  bitfield_bit32_write(0, OTP_CTRL_CHECK_TRIGGER_INTEGRITY_BIT, true);
65  mmio_region_write32(otp->base_addr, OTP_CTRL_CHECK_TRIGGER_REG_OFFSET, reg);
66 
67  return kDifOk;
68 }
69 
70 dif_result_t dif_otp_ctrl_check_consistency(const dif_otp_ctrl_t *otp) {
71  if (otp == NULL) {
72  return kDifBadArg;
73  }
74  if (checks_are_locked(otp, /*check_config=*/false)) {
75  return kDifLocked;
76  }
77 
78  uint32_t reg =
79  bitfield_bit32_write(0, OTP_CTRL_CHECK_TRIGGER_CONSISTENCY_BIT, true);
80  mmio_region_write32(otp->base_addr, OTP_CTRL_CHECK_TRIGGER_REG_OFFSET, reg);
81 
82  return kDifOk;
83 }
84 
85 dif_result_t dif_otp_ctrl_dai_lock(const dif_otp_ctrl_t *otp) {
86  if (otp == NULL) {
87  return kDifBadArg;
88  }
89 
90  uint32_t reg = bitfield_bit32_write(
91  0, OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, false);
92  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
93  reg);
94 
95  return kDifOk;
96 }
97 
98 dif_result_t dif_otp_ctrl_dai_is_locked(const dif_otp_ctrl_t *otp,
99  bool *is_locked) {
100  if (otp == NULL || is_locked == NULL) {
101  return kDifBadArg;
102  }
103 
104  uint32_t reg = mmio_region_read32(otp->base_addr,
105  OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET);
106  *is_locked = !bitfield_bit32_read(
107  reg, OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT);
108 
109  return kDifOk;
110 }
111 
112 dif_result_t dif_otp_ctrl_lock_config(const dif_otp_ctrl_t *otp) {
113  if (otp == NULL) {
114  return kDifBadArg;
115  }
116 
117  uint32_t reg =
118  bitfield_bit32_write(0, OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, false);
119  mmio_region_write32(otp->base_addr, OTP_CTRL_CHECK_REGWEN_REG_OFFSET, reg);
120 
121  return kDifOk;
122 }
123 
124 dif_result_t dif_otp_ctrl_config_is_locked(const dif_otp_ctrl_t *otp,
125  bool *is_locked) {
126  if (otp == NULL || is_locked == NULL) {
127  return kDifBadArg;
128  }
129 
130  *is_locked = checks_are_locked(otp, /*check_config=*/true);
131  return kDifOk;
132 }
133 
134 dif_result_t dif_otp_ctrl_lock_check_trigger(const dif_otp_ctrl_t *otp) {
135  if (otp == NULL) {
136  return kDifBadArg;
137  }
138 
139  uint32_t reg = bitfield_bit32_write(
140  0, OTP_CTRL_CHECK_TRIGGER_REGWEN_CHECK_TRIGGER_REGWEN_BIT, false);
141  mmio_region_write32(otp->base_addr, OTP_CTRL_CHECK_TRIGGER_REGWEN_REG_OFFSET,
142  reg);
143 
144  return kDifOk;
145 }
146 
148  bool *is_locked) {
149  if (otp == NULL || is_locked == NULL) {
150  return kDifBadArg;
151  }
152 
153  *is_locked = checks_are_locked(otp, /*check_config=*/false);
154  return kDifOk;
155 }
156 
157 static bool sw_read_lock_reg_offset(dif_otp_ctrl_partition_t partition,
158  ptrdiff_t *reg_offset,
159  bitfield_bit32_index_t *index) {
160  switch (partition) {
162  *reg_offset = OTP_CTRL_VENDOR_TEST_READ_LOCK_REG_OFFSET;
163  *index = OTP_CTRL_VENDOR_TEST_READ_LOCK_VENDOR_TEST_READ_LOCK_BIT;
164  break;
166  *reg_offset = OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_REG_OFFSET;
167  *index = OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_CREATOR_SW_CFG_READ_LOCK_BIT;
168  break;
170  *reg_offset = OTP_CTRL_OWNER_SW_CFG_READ_LOCK_REG_OFFSET;
171  *index = OTP_CTRL_OWNER_SW_CFG_READ_LOCK_OWNER_SW_CFG_READ_LOCK_BIT;
172  break;
174  *reg_offset = OTP_CTRL_ROT_CREATOR_AUTH_CODESIGN_READ_LOCK_REG_OFFSET;
175  *index =
176  OTP_CTRL_ROT_CREATOR_AUTH_CODESIGN_READ_LOCK_ROT_CREATOR_AUTH_CODESIGN_READ_LOCK_BIT;
177  break;
179  *reg_offset = OTP_CTRL_ROT_CREATOR_AUTH_STATE_READ_LOCK_REG_OFFSET;
180  *index =
181  OTP_CTRL_ROT_CREATOR_AUTH_STATE_READ_LOCK_ROT_CREATOR_AUTH_STATE_READ_LOCK_BIT;
182  break;
183  default:
184  return false;
185  }
186  return true;
187 }
188 
189 dif_result_t dif_otp_ctrl_lock_reading(const dif_otp_ctrl_t *otp,
190  dif_otp_ctrl_partition_t partition) {
191  if (otp == NULL) {
192  return kDifBadArg;
193  }
194 
195  ptrdiff_t offset;
197  if (!sw_read_lock_reg_offset(partition, &offset, &index)) {
198  return kDifBadArg;
199  }
200 
201  uint32_t reg = bitfield_bit32_write(0, index, false);
202  mmio_region_write32(otp->base_addr, offset, reg);
203 
204  return kDifOk;
205 }
206 
208  dif_otp_ctrl_partition_t partition,
209  bool *is_locked) {
210  if (otp == NULL || is_locked == NULL) {
211  return kDifBadArg;
212  }
213 
214  ptrdiff_t offset;
216  if (!sw_read_lock_reg_offset(partition, &offset, &index)) {
217  return kDifBadArg;
218  }
219 
220  uint32_t reg = mmio_region_read32(otp->base_addr, offset);
221  *is_locked = !bitfield_bit32_read(reg, index);
222  return kDifOk;
223 }
224 
225 dif_result_t dif_otp_ctrl_get_status(const dif_otp_ctrl_t *otp,
227  if (otp == NULL || status == NULL) {
228  return kDifBadArg;
229  }
230 
231  static const bitfield_bit32_index_t kIndices[] = {
233  OTP_CTRL_STATUS_VENDOR_TEST_ERROR_BIT,
235  OTP_CTRL_STATUS_CREATOR_SW_CFG_ERROR_BIT,
237  OTP_CTRL_STATUS_OWNER_SW_CFG_ERROR_BIT,
239  OTP_CTRL_STATUS_ROT_CREATOR_AUTH_CODESIGN_ERROR_BIT,
241  OTP_CTRL_STATUS_ROT_CREATOR_AUTH_STATE_ERROR_BIT,
242  [kDifOtpCtrlStatusCodeHwCfg0Error] = OTP_CTRL_STATUS_HW_CFG0_ERROR_BIT,
243  [kDifOtpCtrlStatusCodeHwCfg1Error] = OTP_CTRL_STATUS_HW_CFG1_ERROR_BIT,
244  [kDifOtpCtrlStatusCodeSecret0Error] = OTP_CTRL_STATUS_SECRET0_ERROR_BIT,
245  [kDifOtpCtrlStatusCodeSecret1Error] = OTP_CTRL_STATUS_SECRET1_ERROR_BIT,
246  [kDifOtpCtrlStatusCodeSecret2Error] = OTP_CTRL_STATUS_SECRET2_ERROR_BIT,
248  OTP_CTRL_STATUS_LIFE_CYCLE_ERROR_BIT,
249  [kDifOtpCtrlStatusCodeDaiError] = OTP_CTRL_STATUS_DAI_ERROR_BIT,
250  [kDifOtpCtrlStatusCodeLciError] = OTP_CTRL_STATUS_LCI_ERROR_BIT,
251  [kDifOtpCtrlStatusCodeTimeoutError] = OTP_CTRL_STATUS_TIMEOUT_ERROR_BIT,
252  [kDifOtpCtrlStatusCodeLfsrError] = OTP_CTRL_STATUS_LFSR_FSM_ERROR_BIT,
254  OTP_CTRL_STATUS_SCRAMBLING_FSM_ERROR_BIT,
255  [kDifOtpCtrlStatusCodeKdfError] = OTP_CTRL_STATUS_KEY_DERIV_FSM_ERROR_BIT,
257  OTP_CTRL_STATUS_BUS_INTEG_ERROR_BIT,
258  [kDifOtpCtrlStatusCodeDaiIdle] = OTP_CTRL_STATUS_DAI_IDLE_BIT,
259  [kDifOtpCtrlStatusCodeCheckPending] = OTP_CTRL_STATUS_CHECK_PENDING_BIT,
260  };
261 
262  status->codes = 0;
263  uint32_t status_code =
264  mmio_region_read32(otp->base_addr, OTP_CTRL_STATUS_REG_OFFSET);
265  for (int i = 0; i < ARRAYSIZE(kIndices); ++i) {
266  // If the error is not present at all, we clear its cause bit if relevant,
267  // and bail immediately.
268  if (!bitfield_bit32_read(status_code, kIndices[i])) {
270  status->causes[i] = kDifOtpCtrlErrorOk;
271  }
272  continue;
273  }
274 
275  status->codes =
277 
279  bitfield_field32_t field;
280  field = (bitfield_field32_t){
281  .mask = OTP_CTRL_ERR_CODE_0_ERR_CODE_0_MASK,
282  .index = OTP_CTRL_ERR_CODE_0_ERR_CODE_0_OFFSET,
283  };
284 
285  ptrdiff_t address =
286  OTP_CTRL_ERR_CODE_0_REG_OFFSET + i * (ptrdiff_t)sizeof(uint32_t);
287  uint32_t error_code = mmio_region_read32(otp->base_addr, address);
288 
290  switch (bitfield_field32_read(error_code, field)) {
291  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_NO_ERROR:
292  err = kDifOtpCtrlErrorOk;
293  break;
294  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_MACRO_ERROR:
296  break;
297  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_MACRO_ECC_CORR_ERROR:
299  break;
300  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_MACRO_ECC_UNCORR_ERROR:
302  break;
303  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_MACRO_WRITE_BLANK_ERROR:
305  break;
306  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_ACCESS_ERROR:
308  break;
309  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_CHECK_FAIL_ERROR:
311  break;
312  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_FSM_STATE_ERROR:
314  break;
315  default:
316  return kDifError;
317  }
318  status->causes[i] = err;
319  }
320  }
321 
322  return kDifOk;
323 }
324 
325 typedef struct partition_info {
326  /**
327  * The absolute OTP address at which this partition starts.
328  */
329  uint32_t start_addr;
330  /**
331  * The length of this partition, in bytes, including the digest.
332  *
333  * If the partition has a digest, it is expected to be at address
334  * `start_addr + len - sizeof(uint64_t)`.
335  */
336  uint32_t len;
337  /**
338  * The alignment mask for this partition.
339  *
340  * A valid address for this partition must be such that
341  * `addr & align_mask == 0`.
342  */
343  uint32_t align_mask;
344 
345  /**
346  * Whether this is a software-managed partition with a software-managed
347  * digest.
348  */
350 
351  /**
352  * Whether this partition has a digest field.
353  */
355 
356  /**
357  * Whether this partition is the lifecycle partition.
358  */
361 
362 // This is generates too many lines with different formatting variants, so
363 // We opt to just disable formatting.
364 // clang-format off
365 static const partition_info_t kPartitions[] = {
367  .start_addr = OTP_CTRL_PARAM_VENDOR_TEST_OFFSET,
368  .len = OTP_CTRL_PARAM_VENDOR_TEST_SIZE,
369  .align_mask = 0x3,
370  .is_software = true,
371  .has_digest = true,
372  .is_lifecycle = false},
374  .start_addr = OTP_CTRL_PARAM_CREATOR_SW_CFG_OFFSET,
375  .len = OTP_CTRL_PARAM_CREATOR_SW_CFG_SIZE,
376  .align_mask = 0x3,
377  .is_software = true,
378  .has_digest = true,
379  .is_lifecycle = false},
381  .start_addr = OTP_CTRL_PARAM_OWNER_SW_CFG_OFFSET,
382  .len = OTP_CTRL_PARAM_OWNER_SW_CFG_SIZE,
383  .align_mask = 0x3,
384  .is_software = true,
385  .has_digest = true,
386  .is_lifecycle = false},
388  .start_addr = OTP_CTRL_PARAM_ROT_CREATOR_AUTH_CODESIGN_OFFSET,
389  .len = OTP_CTRL_PARAM_ROT_CREATOR_AUTH_CODESIGN_SIZE,
390  .align_mask = 0x3,
391  .is_software = true,
392  .has_digest = true,
393  .is_lifecycle = false},
395  .start_addr = OTP_CTRL_PARAM_ROT_CREATOR_AUTH_STATE_OFFSET,
396  .len = OTP_CTRL_PARAM_ROT_CREATOR_AUTH_STATE_SIZE,
397  .align_mask = 0x3,
398  .is_software = true,
399  .has_digest = true,
400  .is_lifecycle = false},
402  .start_addr = OTP_CTRL_PARAM_HW_CFG0_OFFSET,
403  .len = OTP_CTRL_PARAM_HW_CFG0_SIZE,
404  .align_mask = 0x3,
405  .is_software = false,
406  .has_digest = true,
407  .is_lifecycle = false},
409  .start_addr = OTP_CTRL_PARAM_HW_CFG1_OFFSET,
410  .len = OTP_CTRL_PARAM_HW_CFG1_SIZE,
411  .align_mask = 0x3,
412  .is_software = false,
413  .has_digest = true,
414  .is_lifecycle = false},
416  .start_addr = OTP_CTRL_PARAM_SECRET0_OFFSET,
417  .len = OTP_CTRL_PARAM_SECRET0_SIZE,
418  .align_mask = 0x7,
419  .is_software = false,
420  .has_digest = true,
421  .is_lifecycle = false},
423  .start_addr = OTP_CTRL_PARAM_SECRET1_OFFSET,
424  .len = OTP_CTRL_PARAM_SECRET1_SIZE,
425  .align_mask = 0x7,
426  .is_software = false,
427  .has_digest = true,
428  .is_lifecycle = false},
430  .start_addr = OTP_CTRL_PARAM_SECRET2_OFFSET,
431  .len = OTP_CTRL_PARAM_SECRET2_SIZE,
432  .align_mask = 0x7,
433  .is_software = false,
434  .has_digest = true,
435  .is_lifecycle = false},
437  .start_addr = OTP_CTRL_PARAM_LIFE_CYCLE_OFFSET,
438  .len = OTP_CTRL_PARAM_LIFE_CYCLE_SIZE,
439  .align_mask = 0x3,
440  .is_software = false,
441  .has_digest = false,
442  .is_lifecycle = true},
443 };
444 // clang-format on
445 
447  uint32_t abs_address,
448  uint32_t *relative_address) {
449  *relative_address = 0;
450 
451  if (partition >= ARRAYSIZE(kPartitions)) {
452  return kDifBadArg;
453  }
454 
455  if ((abs_address & kPartitions[partition].align_mask) != 0) {
456  return kDifUnaligned;
457  }
458 
459  if (abs_address < kPartitions[partition].start_addr) {
460  return kDifOutOfRange;
461  }
462 
463  *relative_address = abs_address - kPartitions[partition].start_addr;
464  if (*relative_address >= kPartitions[partition].len) {
465  *relative_address = 0;
466  return kDifOutOfRange;
467  }
468 
469  return kDifOk;
470 }
471 
472 dif_result_t dif_otp_ctrl_dai_read_start(const dif_otp_ctrl_t *otp,
473  dif_otp_ctrl_partition_t partition,
474  uint32_t address) {
475  if (otp == NULL || partition >= ARRAYSIZE(kPartitions)) {
476  return kDifBadArg;
477  }
478 
479  if ((address & kPartitions[partition].align_mask) != 0) {
480  return kDifUnaligned;
481  }
482 
483  if (address >= kPartitions[partition].len) {
484  return kDifOutOfRange;
485  }
486 
487  address += kPartitions[partition].start_addr;
488  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
489  address);
490 
491  uint32_t cmd =
492  bitfield_bit32_write(0, OTP_CTRL_DIRECT_ACCESS_CMD_RD_BIT, true);
493  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
494  cmd);
495 
496  return kDifOk;
497 }
498 
499 dif_result_t dif_otp_ctrl_dai_read32_end(const dif_otp_ctrl_t *otp,
500  uint32_t *value) {
501  if (otp == NULL || value == NULL) {
502  return kDifBadArg;
503  }
504 
505  *value = mmio_region_read32(otp->base_addr,
506  OTP_CTRL_DIRECT_ACCESS_RDATA_0_REG_OFFSET);
507  return kDifOk;
508 }
509 
510 dif_result_t dif_otp_ctrl_dai_read64_end(const dif_otp_ctrl_t *otp,
511  uint64_t *value) {
512  if (otp == NULL || value == NULL) {
513  return kDifBadArg;
514  }
515 
516  *value = mmio_region_read32(otp->base_addr,
517  OTP_CTRL_DIRECT_ACCESS_RDATA_1_REG_OFFSET);
518  *value <<= 32;
519  *value |= mmio_region_read32(otp->base_addr,
520  OTP_CTRL_DIRECT_ACCESS_RDATA_0_REG_OFFSET);
521  return kDifOk;
522 }
523 
524 dif_result_t dif_otp_ctrl_dai_program32(const dif_otp_ctrl_t *otp,
525  dif_otp_ctrl_partition_t partition,
526  uint32_t address, uint32_t value) {
527  if (otp == NULL || partition >= ARRAYSIZE(kPartitions)) {
528  return kDifBadArg;
529  }
530 
531  // Ensure that we are writing to a 32-bit-access partition by checking that
532  // the alignment mask is 0b11.
533  //
534  // Note furthermore that the LC partition is *not* writeable, so we eject
535  // here.
536  if (kPartitions[partition].align_mask != 0x3 ||
537  kPartitions[partition].is_lifecycle) {
538  return kDifError;
539  }
540 
541  if ((address & kPartitions[partition].align_mask) != 0) {
542  return kDifUnaligned;
543  }
544 
545  // NOTE: The bounds check is tightened here, since we disallow writing the
546  // digest directly. If the partition does not have a digest, no tightening is
547  // needed.
548  size_t digest_size = kPartitions[partition].has_digest * sizeof(uint64_t);
549  if (address >= kPartitions[partition].len - digest_size) {
550  return kDifOutOfRange;
551  }
552 
553  address += kPartitions[partition].start_addr;
554  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
555  address);
556 
557  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_WDATA_0_REG_OFFSET,
558  value);
559 
560  uint32_t cmd =
561  bitfield_bit32_write(0, OTP_CTRL_DIRECT_ACCESS_CMD_WR_BIT, true);
562  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
563  cmd);
564 
565  return kDifOk;
566 }
567 
568 dif_result_t dif_otp_ctrl_dai_program64(const dif_otp_ctrl_t *otp,
569  dif_otp_ctrl_partition_t partition,
570  uint32_t address, uint64_t value) {
571  if (otp == NULL || partition >= ARRAYSIZE(kPartitions)) {
572  return kDifBadArg;
573  }
574 
575  // Ensure that we are writing to a 64-bit-access partition by checking that
576  // the alignment mask is 0b111.
577  if (kPartitions[partition].align_mask != 0x7) {
578  return kDifError;
579  }
580 
581  if ((address & kPartitions[partition].align_mask) != 0) {
582  return kDifUnaligned;
583  }
584 
585  // NOTE: The bounds check is tightened here, since we disallow writing the
586  // digest directly.
587  size_t digest_size = sizeof(uint64_t);
588  if (address >= kPartitions[partition].len - digest_size) {
589  return kDifOutOfRange;
590  }
591 
592  address += kPartitions[partition].start_addr;
593  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
594  address);
595 
596  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_WDATA_0_REG_OFFSET,
597  value & UINT32_MAX);
598  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_WDATA_1_REG_OFFSET,
599  value >> 32);
600 
601  uint32_t cmd =
602  bitfield_bit32_write(0, OTP_CTRL_DIRECT_ACCESS_CMD_WR_BIT, true);
603  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
604  cmd);
605 
606  return kDifOk;
607 }
608 
609 dif_result_t dif_otp_ctrl_dai_digest(const dif_otp_ctrl_t *otp,
610  dif_otp_ctrl_partition_t partition,
611  uint64_t digest) {
612  if (otp == NULL || partition >= ARRAYSIZE(kPartitions)) {
613  return kDifBadArg;
614  }
615 
616  // Not all partitions have a digest.
617  if (!kPartitions[partition].has_digest) {
618  return kDifError;
619  }
620 
621  // For software partitions, the digest must be nonzero; for all other
622  // partitions it must be zero.
623  bool is_sw = kPartitions[partition].is_software;
624  if (is_sw == (digest == 0)) {
625  return kDifBadArg;
626  }
627 
628  uint32_t address = kPartitions[partition].start_addr;
629  if (is_sw) {
630  address += kPartitions[partition].len - sizeof(digest);
631  }
632  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
633  address);
634 
635  if (digest != 0) {
636  mmio_region_write32(otp->base_addr,
637  OTP_CTRL_DIRECT_ACCESS_WDATA_0_REG_OFFSET,
638  digest & 0xffffffff);
639  mmio_region_write32(otp->base_addr,
640  OTP_CTRL_DIRECT_ACCESS_WDATA_1_REG_OFFSET,
641  digest >> 32);
642  }
643 
644  bitfield_bit32_index_t cmd_bit = is_sw
645  ? OTP_CTRL_DIRECT_ACCESS_CMD_WR_BIT
646  : OTP_CTRL_DIRECT_ACCESS_CMD_DIGEST_BIT;
647  uint32_t cmd = bitfield_bit32_write(0, cmd_bit, true);
648  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
649  cmd);
650 
651  return kDifOk;
652 }
653 
654 static bool get_digest_regs(dif_otp_ctrl_partition_t partition, ptrdiff_t *reg0,
655  ptrdiff_t *reg1) {
656  switch (partition) {
658  *reg0 = OTP_CTRL_VENDOR_TEST_DIGEST_0_REG_OFFSET;
659  *reg1 = OTP_CTRL_VENDOR_TEST_DIGEST_1_REG_OFFSET;
660  break;
662  *reg0 = OTP_CTRL_CREATOR_SW_CFG_DIGEST_0_REG_OFFSET;
663  *reg1 = OTP_CTRL_CREATOR_SW_CFG_DIGEST_1_REG_OFFSET;
664  break;
666  *reg0 = OTP_CTRL_OWNER_SW_CFG_DIGEST_0_REG_OFFSET;
667  *reg1 = OTP_CTRL_OWNER_SW_CFG_DIGEST_1_REG_OFFSET;
668  break;
670  *reg0 = OTP_CTRL_ROT_CREATOR_AUTH_CODESIGN_DIGEST_0_REG_OFFSET;
671  *reg1 = OTP_CTRL_ROT_CREATOR_AUTH_CODESIGN_DIGEST_1_REG_OFFSET;
672  break;
674  *reg0 = OTP_CTRL_ROT_CREATOR_AUTH_STATE_DIGEST_0_REG_OFFSET;
675  *reg1 = OTP_CTRL_ROT_CREATOR_AUTH_STATE_DIGEST_1_REG_OFFSET;
676  break;
678  *reg0 = OTP_CTRL_HW_CFG0_DIGEST_0_REG_OFFSET;
679  *reg1 = OTP_CTRL_HW_CFG0_DIGEST_1_REG_OFFSET;
680  break;
682  *reg0 = OTP_CTRL_HW_CFG1_DIGEST_0_REG_OFFSET;
683  *reg1 = OTP_CTRL_HW_CFG1_DIGEST_1_REG_OFFSET;
684  break;
686  *reg0 = OTP_CTRL_SECRET0_DIGEST_0_REG_OFFSET;
687  *reg1 = OTP_CTRL_SECRET0_DIGEST_1_REG_OFFSET;
688  break;
690  *reg0 = OTP_CTRL_SECRET1_DIGEST_0_REG_OFFSET;
691  *reg1 = OTP_CTRL_SECRET1_DIGEST_1_REG_OFFSET;
692  break;
694  *reg0 = OTP_CTRL_SECRET2_DIGEST_0_REG_OFFSET;
695  *reg1 = OTP_CTRL_SECRET2_DIGEST_1_REG_OFFSET;
696  break;
697  default:
698  return false;
699  }
700 
701  return true;
702 }
703 
705  dif_otp_ctrl_partition_t partition,
706  bool *is_computed) {
707  if (otp == NULL || is_computed == NULL) {
708  return kDifBadArg;
709  }
710 
711  ptrdiff_t reg0, reg1;
712  if (!get_digest_regs(partition, &reg0, &reg1)) {
713  return kDifBadArg;
714  }
715 
716  uint64_t value = mmio_region_read32(otp->base_addr, reg1);
717  value <<= 32;
718  value |= mmio_region_read32(otp->base_addr, reg0);
719 
720  *is_computed = value != 0;
721 
722  return kDifOk;
723 }
724 
725 dif_result_t dif_otp_ctrl_get_digest(const dif_otp_ctrl_t *otp,
726  dif_otp_ctrl_partition_t partition,
727  uint64_t *digest) {
728  if (otp == NULL || digest == NULL) {
729  return kDifBadArg;
730  }
731 
732  ptrdiff_t reg0, reg1;
733  if (!get_digest_regs(partition, &reg0, &reg1)) {
734  return kDifBadArg;
735  }
736 
737  uint64_t value = mmio_region_read32(otp->base_addr, reg1);
738  value <<= 32;
739  value |= mmio_region_read32(otp->base_addr, reg0);
740 
741  if (value == 0) {
742  return kDifError;
743  }
744  *digest = value;
745 
746  return kDifOk;
747 }
748 
749 dif_result_t dif_otp_ctrl_read_blocking(const dif_otp_ctrl_t *otp,
750  dif_otp_ctrl_partition_t partition,
751  uint32_t address, uint32_t *buf,
752  size_t len) {
753  if (otp == NULL || partition >= ARRAYSIZE(kPartitions) || buf == NULL) {
754  return kDifBadArg;
755  }
756 
757  if (!kPartitions[partition].is_software) {
758  return kDifError;
759  }
760 
761  if ((address & kPartitions[partition].align_mask) != 0) {
762  return kDifUnaligned;
763  }
764 
765  if (address + len >= kPartitions[partition].len) {
766  return kDifOutOfRange;
767  }
768 
769  uint32_t reg_offset = OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET +
770  kPartitions[partition].start_addr + address;
771  mmio_region_memcpy_from_mmio32(otp->base_addr, reg_offset, buf,
772  len * sizeof(uint32_t));
773  return kDifOk;
774 }