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