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 busy = mmio_region_read32(otp->base_addr,
205  OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET);
206  if (!bitfield_bit32_read(
207  busy, OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT)) {
208  return kDifUnavailable;
209  }
210 
211  uint32_t reg = bitfield_bit32_write(0, index, false);
212  mmio_region_write32(otp->base_addr, offset, reg);
213 
214  return kDifOk;
215 }
216 
218  dif_otp_ctrl_partition_t partition,
219  bool *is_locked) {
220  if (otp == NULL || is_locked == NULL) {
221  return kDifBadArg;
222  }
223 
224  ptrdiff_t offset;
226  if (!sw_read_lock_reg_offset(partition, &offset, &index)) {
227  return kDifBadArg;
228  }
229 
230  uint32_t reg = mmio_region_read32(otp->base_addr, offset);
231  *is_locked = !bitfield_bit32_read(reg, index);
232  return kDifOk;
233 }
234 
237  if (otp == NULL || status == NULL) {
238  return kDifBadArg;
239  }
240 
241  static const bitfield_bit32_index_t kIndices[] = {
243  OTP_CTRL_STATUS_VENDOR_TEST_ERROR_BIT,
245  OTP_CTRL_STATUS_CREATOR_SW_CFG_ERROR_BIT,
247  OTP_CTRL_STATUS_OWNER_SW_CFG_ERROR_BIT,
249  OTP_CTRL_STATUS_ROT_CREATOR_AUTH_CODESIGN_ERROR_BIT,
251  OTP_CTRL_STATUS_ROT_CREATOR_AUTH_STATE_ERROR_BIT,
252  [kDifOtpCtrlStatusCodeHwCfg0Error] = OTP_CTRL_STATUS_HW_CFG0_ERROR_BIT,
253  [kDifOtpCtrlStatusCodeHwCfg1Error] = OTP_CTRL_STATUS_HW_CFG1_ERROR_BIT,
254  [kDifOtpCtrlStatusCodeSecret0Error] = OTP_CTRL_STATUS_SECRET0_ERROR_BIT,
255  [kDifOtpCtrlStatusCodeSecret1Error] = OTP_CTRL_STATUS_SECRET1_ERROR_BIT,
256  [kDifOtpCtrlStatusCodeSecret2Error] = OTP_CTRL_STATUS_SECRET2_ERROR_BIT,
258  OTP_CTRL_STATUS_LIFE_CYCLE_ERROR_BIT,
259  [kDifOtpCtrlStatusCodeDaiError] = OTP_CTRL_STATUS_DAI_ERROR_BIT,
260  [kDifOtpCtrlStatusCodeLciError] = OTP_CTRL_STATUS_LCI_ERROR_BIT,
261  [kDifOtpCtrlStatusCodeTimeoutError] = OTP_CTRL_STATUS_TIMEOUT_ERROR_BIT,
262  [kDifOtpCtrlStatusCodeLfsrError] = OTP_CTRL_STATUS_LFSR_FSM_ERROR_BIT,
264  OTP_CTRL_STATUS_SCRAMBLING_FSM_ERROR_BIT,
265  [kDifOtpCtrlStatusCodeKdfError] = OTP_CTRL_STATUS_KEY_DERIV_FSM_ERROR_BIT,
267  OTP_CTRL_STATUS_BUS_INTEG_ERROR_BIT,
268  [kDifOtpCtrlStatusCodeDaiIdle] = OTP_CTRL_STATUS_DAI_IDLE_BIT,
269  [kDifOtpCtrlStatusCodeCheckPending] = OTP_CTRL_STATUS_CHECK_PENDING_BIT,
270  };
271 
272  status->codes = 0;
273  uint32_t status_code =
274  mmio_region_read32(otp->base_addr, OTP_CTRL_STATUS_REG_OFFSET);
275  for (int i = 0; i < ARRAYSIZE(kIndices); ++i) {
276  // If the error is not present at all, we clear its cause bit if relevant,
277  // and bail immediately.
278  if (!bitfield_bit32_read(status_code, kIndices[i])) {
280  status->causes[i] = kDifOtpCtrlErrorOk;
281  }
282  continue;
283  }
284 
285  status->codes =
287 
289  bitfield_field32_t field;
290  field = (bitfield_field32_t){
291  .mask = OTP_CTRL_ERR_CODE_0_ERR_CODE_0_MASK,
292  .index = OTP_CTRL_ERR_CODE_0_ERR_CODE_0_OFFSET,
293  };
294 
295  ptrdiff_t address =
296  OTP_CTRL_ERR_CODE_0_REG_OFFSET + i * (ptrdiff_t)sizeof(uint32_t);
297  uint32_t error_code = mmio_region_read32(otp->base_addr, address);
298 
300  switch (bitfield_field32_read(error_code, field)) {
301  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_NO_ERROR:
302  err = kDifOtpCtrlErrorOk;
303  break;
304  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_MACRO_ERROR:
306  break;
307  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_MACRO_ECC_CORR_ERROR:
309  break;
310  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_MACRO_ECC_UNCORR_ERROR:
312  break;
313  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_MACRO_WRITE_BLANK_ERROR:
315  break;
316  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_ACCESS_ERROR:
318  break;
319  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_CHECK_FAIL_ERROR:
321  break;
322  case OTP_CTRL_ERR_CODE_0_ERR_CODE_0_VALUE_FSM_STATE_ERROR:
324  break;
325  default:
326  return kDifError;
327  }
328  status->causes[i] = err;
329  }
330  }
331 
332  return kDifOk;
333 }
334 
335 typedef struct partition_info {
336  /**
337  * The absolute OTP address at which this partition starts.
338  */
339  uint32_t start_addr;
340  /**
341  * The length of this partition, in bytes, including the digest.
342  *
343  * If the partition has a digest, it is expected to be at address
344  * `start_addr + len - sizeof(uint64_t)`.
345  */
346  uint32_t len;
347  /**
348  * The alignment mask for this partition.
349  *
350  * A valid address for this partition must be such that
351  * `addr & align_mask == 0`.
352  */
353  uint32_t align_mask;
354 
355  /**
356  * Whether this is a software-managed partition with a software-managed
357  * digest.
358  */
360 
361  /**
362  * Whether this partition has a digest field.
363  */
365 
366  /**
367  * Whether this partition is the lifecycle partition.
368  */
371 
372 // This is generates too many lines with different formatting variants, so
373 // We opt to just disable formatting.
374 // clang-format off
375 static const partition_info_t kPartitions[] = {
377  .start_addr = OTP_CTRL_PARAM_VENDOR_TEST_OFFSET,
378  .len = OTP_CTRL_PARAM_VENDOR_TEST_SIZE,
379  .align_mask = 0x3,
380  .is_software = true,
381  .has_digest = true,
382  .is_lifecycle = false},
384  .start_addr = OTP_CTRL_PARAM_CREATOR_SW_CFG_OFFSET,
385  .len = OTP_CTRL_PARAM_CREATOR_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_OWNER_SW_CFG_OFFSET,
392  .len = OTP_CTRL_PARAM_OWNER_SW_CFG_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_CODESIGN_OFFSET,
399  .len = OTP_CTRL_PARAM_ROT_CREATOR_AUTH_CODESIGN_SIZE,
400  .align_mask = 0x3,
401  .is_software = true,
402  .has_digest = true,
403  .is_lifecycle = false},
405  .start_addr = OTP_CTRL_PARAM_ROT_CREATOR_AUTH_STATE_OFFSET,
406  .len = OTP_CTRL_PARAM_ROT_CREATOR_AUTH_STATE_SIZE,
407  .align_mask = 0x3,
408  .is_software = true,
409  .has_digest = true,
410  .is_lifecycle = false},
412  .start_addr = OTP_CTRL_PARAM_HW_CFG0_OFFSET,
413  .len = OTP_CTRL_PARAM_HW_CFG0_SIZE,
414  .align_mask = 0x3,
415  .is_software = false,
416  .has_digest = true,
417  .is_lifecycle = false},
419  .start_addr = OTP_CTRL_PARAM_HW_CFG1_OFFSET,
420  .len = OTP_CTRL_PARAM_HW_CFG1_SIZE,
421  .align_mask = 0x3,
422  .is_software = false,
423  .has_digest = true,
424  .is_lifecycle = false},
426  .start_addr = OTP_CTRL_PARAM_SECRET0_OFFSET,
427  .len = OTP_CTRL_PARAM_SECRET0_SIZE,
428  .align_mask = 0x7,
429  .is_software = false,
430  .has_digest = true,
431  .is_lifecycle = false},
433  .start_addr = OTP_CTRL_PARAM_SECRET1_OFFSET,
434  .len = OTP_CTRL_PARAM_SECRET1_SIZE,
435  .align_mask = 0x7,
436  .is_software = false,
437  .has_digest = true,
438  .is_lifecycle = false},
440  .start_addr = OTP_CTRL_PARAM_SECRET2_OFFSET,
441  .len = OTP_CTRL_PARAM_SECRET2_SIZE,
442  .align_mask = 0x7,
443  .is_software = false,
444  .has_digest = true,
445  .is_lifecycle = false},
447  .start_addr = OTP_CTRL_PARAM_LIFE_CYCLE_OFFSET,
448  .len = OTP_CTRL_PARAM_LIFE_CYCLE_SIZE,
449  .align_mask = 0x3,
450  .is_software = false,
451  .has_digest = false,
452  .is_lifecycle = true},
453 };
454 // clang-format on
455 
457  uint32_t abs_address,
458  uint32_t *relative_address) {
459  *relative_address = 0;
460 
461  if (partition >= ARRAYSIZE(kPartitions)) {
462  return kDifBadArg;
463  }
464 
465  if ((abs_address & kPartitions[partition].align_mask) != 0) {
466  return kDifUnaligned;
467  }
468 
469  if (abs_address < kPartitions[partition].start_addr) {
470  return kDifOutOfRange;
471  }
472 
473  *relative_address = abs_address - kPartitions[partition].start_addr;
474  if (*relative_address >= kPartitions[partition].len) {
475  *relative_address = 0;
476  return kDifOutOfRange;
477  }
478 
479  return kDifOk;
480 }
481 
483  dif_otp_ctrl_partition_t partition,
484  uint32_t address) {
485  if (otp == NULL || partition >= ARRAYSIZE(kPartitions)) {
486  return kDifBadArg;
487  }
488 
489  if ((address & kPartitions[partition].align_mask) != 0) {
490  return kDifUnaligned;
491  }
492 
493  if (address >= kPartitions[partition].len) {
494  return kDifOutOfRange;
495  }
496 
497  uint32_t busy = mmio_region_read32(otp->base_addr,
498  OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET);
499  if (!bitfield_bit32_read(
500  busy, OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT)) {
501  return kDifUnavailable;
502  }
503 
504  address += kPartitions[partition].start_addr;
505  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
506  address);
507 
508  uint32_t cmd =
509  bitfield_bit32_write(0, OTP_CTRL_DIRECT_ACCESS_CMD_RD_BIT, true);
510  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
511  cmd);
512 
513  return kDifOk;
514 }
515 
517  uint32_t *value) {
518  if (otp == NULL || value == NULL) {
519  return kDifBadArg;
520  }
521 
522  uint32_t busy = mmio_region_read32(otp->base_addr,
523  OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET);
524  if (!bitfield_bit32_read(
525  busy, OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT)) {
526  return kDifUnavailable;
527  }
528 
529  *value = mmio_region_read32(otp->base_addr,
530  OTP_CTRL_DIRECT_ACCESS_RDATA_0_REG_OFFSET);
531  return kDifOk;
532 }
533 
535  uint64_t *value) {
536  if (otp == NULL || value == NULL) {
537  return kDifBadArg;
538  }
539 
540  uint32_t busy = mmio_region_read32(otp->base_addr,
541  OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET);
542  if (!bitfield_bit32_read(
543  busy, OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT)) {
544  return kDifUnavailable;
545  }
546 
547  *value = mmio_region_read32(otp->base_addr,
548  OTP_CTRL_DIRECT_ACCESS_RDATA_1_REG_OFFSET);
549  *value <<= 32;
550  *value |= mmio_region_read32(otp->base_addr,
551  OTP_CTRL_DIRECT_ACCESS_RDATA_0_REG_OFFSET);
552  return kDifOk;
553 }
554 
556  dif_otp_ctrl_partition_t partition,
557  uint32_t address, uint32_t value) {
558  if (otp == NULL || partition >= ARRAYSIZE(kPartitions)) {
559  return kDifBadArg;
560  }
561 
562  // Ensure that we are writing to a 32-bit-access partition by checking that
563  // the alignment mask is 0b11.
564  //
565  // Note furthermore that the LC partition is *not* writeable, so we eject
566  // here.
567  if (kPartitions[partition].align_mask != 0x3 ||
568  kPartitions[partition].is_lifecycle) {
569  return kDifError;
570  }
571 
572  if ((address & kPartitions[partition].align_mask) != 0) {
573  return kDifUnaligned;
574  }
575 
576  // NOTE: The bounds check is tightened here, since we disallow writing the
577  // digest directly. If the partition does not have a digest, no tightening is
578  // needed.
579  size_t digest_size = kPartitions[partition].has_digest * sizeof(uint64_t);
580  if (address >= kPartitions[partition].len - digest_size) {
581  return kDifOutOfRange;
582  }
583 
584  uint32_t busy = mmio_region_read32(otp->base_addr,
585  OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET);
586  if (!bitfield_bit32_read(
587  busy, OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT)) {
588  return kDifUnavailable;
589  }
590 
591  address += kPartitions[partition].start_addr;
592  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
593  address);
594 
595  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_WDATA_0_REG_OFFSET,
596  value);
597 
598  uint32_t cmd =
599  bitfield_bit32_write(0, OTP_CTRL_DIRECT_ACCESS_CMD_WR_BIT, true);
600  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
601  cmd);
602 
603  return kDifOk;
604 }
605 
607  dif_otp_ctrl_partition_t partition,
608  uint32_t address, uint64_t value) {
609  if (otp == NULL || partition >= ARRAYSIZE(kPartitions)) {
610  return kDifBadArg;
611  }
612 
613  // Ensure that we are writing to a 64-bit-access partition by checking that
614  // the alignment mask is 0b111.
615  if (kPartitions[partition].align_mask != 0x7) {
616  return kDifError;
617  }
618 
619  if ((address & kPartitions[partition].align_mask) != 0) {
620  return kDifUnaligned;
621  }
622 
623  // NOTE: The bounds check is tightened here, since we disallow writing the
624  // digest directly.
625  size_t digest_size = sizeof(uint64_t);
626  if (address >= kPartitions[partition].len - digest_size) {
627  return kDifOutOfRange;
628  }
629 
630  uint32_t busy = mmio_region_read32(otp->base_addr,
631  OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET);
632  if (!bitfield_bit32_read(
633  busy, OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT)) {
634  return kDifUnavailable;
635  }
636 
637  address += kPartitions[partition].start_addr;
638  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
639  address);
640 
641  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_WDATA_0_REG_OFFSET,
642  value & UINT32_MAX);
643  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_WDATA_1_REG_OFFSET,
644  value >> 32);
645 
646  uint32_t cmd =
647  bitfield_bit32_write(0, OTP_CTRL_DIRECT_ACCESS_CMD_WR_BIT, true);
648  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
649  cmd);
650 
651  return kDifOk;
652 }
653 
655  dif_otp_ctrl_partition_t partition,
656  uint64_t digest) {
657  if (otp == NULL || partition >= ARRAYSIZE(kPartitions)) {
658  return kDifBadArg;
659  }
660 
661  // Not all partitions have a digest.
662  if (!kPartitions[partition].has_digest) {
663  return kDifError;
664  }
665 
666  // For software partitions, the digest must be nonzero; for all other
667  // partitions it must be zero.
668  bool is_sw = kPartitions[partition].is_software;
669  if (is_sw == (digest == 0)) {
670  return kDifBadArg;
671  }
672 
673  uint32_t busy = mmio_region_read32(otp->base_addr,
674  OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET);
675  if (!bitfield_bit32_read(
676  busy, OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT)) {
677  return kDifUnavailable;
678  }
679 
680  uint32_t address = kPartitions[partition].start_addr;
681  if (is_sw) {
682  address += kPartitions[partition].len - sizeof(digest);
683  }
684  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
685  address);
686 
687  if (digest != 0) {
688  mmio_region_write32(otp->base_addr,
689  OTP_CTRL_DIRECT_ACCESS_WDATA_0_REG_OFFSET,
690  digest & 0xffffffff);
691  mmio_region_write32(otp->base_addr,
692  OTP_CTRL_DIRECT_ACCESS_WDATA_1_REG_OFFSET,
693  digest >> 32);
694  }
695 
696  bitfield_bit32_index_t cmd_bit = is_sw
697  ? OTP_CTRL_DIRECT_ACCESS_CMD_WR_BIT
698  : OTP_CTRL_DIRECT_ACCESS_CMD_DIGEST_BIT;
699  uint32_t cmd = bitfield_bit32_write(0, cmd_bit, true);
700  mmio_region_write32(otp->base_addr, OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
701  cmd);
702 
703  return kDifOk;
704 }
705 
706 static bool get_digest_regs(dif_otp_ctrl_partition_t partition, ptrdiff_t *reg0,
707  ptrdiff_t *reg1) {
708  switch (partition) {
710  *reg0 = OTP_CTRL_VENDOR_TEST_DIGEST_0_REG_OFFSET;
711  *reg1 = OTP_CTRL_VENDOR_TEST_DIGEST_1_REG_OFFSET;
712  break;
714  *reg0 = OTP_CTRL_CREATOR_SW_CFG_DIGEST_0_REG_OFFSET;
715  *reg1 = OTP_CTRL_CREATOR_SW_CFG_DIGEST_1_REG_OFFSET;
716  break;
718  *reg0 = OTP_CTRL_OWNER_SW_CFG_DIGEST_0_REG_OFFSET;
719  *reg1 = OTP_CTRL_OWNER_SW_CFG_DIGEST_1_REG_OFFSET;
720  break;
722  *reg0 = OTP_CTRL_ROT_CREATOR_AUTH_CODESIGN_DIGEST_0_REG_OFFSET;
723  *reg1 = OTP_CTRL_ROT_CREATOR_AUTH_CODESIGN_DIGEST_1_REG_OFFSET;
724  break;
726  *reg0 = OTP_CTRL_ROT_CREATOR_AUTH_STATE_DIGEST_0_REG_OFFSET;
727  *reg1 = OTP_CTRL_ROT_CREATOR_AUTH_STATE_DIGEST_1_REG_OFFSET;
728  break;
730  *reg0 = OTP_CTRL_HW_CFG0_DIGEST_0_REG_OFFSET;
731  *reg1 = OTP_CTRL_HW_CFG0_DIGEST_1_REG_OFFSET;
732  break;
734  *reg0 = OTP_CTRL_HW_CFG1_DIGEST_0_REG_OFFSET;
735  *reg1 = OTP_CTRL_HW_CFG1_DIGEST_1_REG_OFFSET;
736  break;
738  *reg0 = OTP_CTRL_SECRET0_DIGEST_0_REG_OFFSET;
739  *reg1 = OTP_CTRL_SECRET0_DIGEST_1_REG_OFFSET;
740  break;
742  *reg0 = OTP_CTRL_SECRET1_DIGEST_0_REG_OFFSET;
743  *reg1 = OTP_CTRL_SECRET1_DIGEST_1_REG_OFFSET;
744  break;
746  *reg0 = OTP_CTRL_SECRET2_DIGEST_0_REG_OFFSET;
747  *reg1 = OTP_CTRL_SECRET2_DIGEST_1_REG_OFFSET;
748  break;
749  default:
750  return false;
751  }
752 
753  return true;
754 }
755 
757  dif_otp_ctrl_partition_t partition,
758  bool *is_computed) {
759  if (otp == NULL || is_computed == NULL) {
760  return kDifBadArg;
761  }
762 
763  ptrdiff_t reg0, reg1;
764  if (!get_digest_regs(partition, &reg0, &reg1)) {
765  return kDifBadArg;
766  }
767 
768  uint64_t value = mmio_region_read32(otp->base_addr, reg1);
769  value <<= 32;
770  value |= mmio_region_read32(otp->base_addr, reg0);
771 
772  *is_computed = value != 0;
773 
774  return kDifOk;
775 }
776 
778  dif_otp_ctrl_partition_t partition,
779  uint64_t *digest) {
780  if (otp == NULL || digest == NULL) {
781  return kDifBadArg;
782  }
783 
784  ptrdiff_t reg0, reg1;
785  if (!get_digest_regs(partition, &reg0, &reg1)) {
786  return kDifBadArg;
787  }
788 
789  uint64_t value = mmio_region_read32(otp->base_addr, reg1);
790  value <<= 32;
791  value |= mmio_region_read32(otp->base_addr, reg0);
792 
793  if (value == 0) {
794  return kDifError;
795  }
796  *digest = value;
797 
798  return kDifOk;
799 }
800 
802  dif_otp_ctrl_partition_t partition,
803  uint32_t address, uint32_t *buf,
804  size_t len) {
805  if (otp == NULL || partition >= ARRAYSIZE(kPartitions) || buf == NULL) {
806  return kDifBadArg;
807  }
808 
809  if (!kPartitions[partition].is_software) {
810  return kDifError;
811  }
812 
813  if ((address & kPartitions[partition].align_mask) != 0) {
814  return kDifUnaligned;
815  }
816 
817  if (address + len >= kPartitions[partition].len) {
818  return kDifOutOfRange;
819  }
820 
821  uint32_t reg_offset = OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET +
822  kPartitions[partition].start_addr + address;
823  mmio_region_memcpy_from_mmio32(otp->base_addr, reg_offset, buf,
824  len * sizeof(uint32_t));
825  return kDifOk;
826 }