[dif/edn] Wrap up remaining EDN DIFs

Signed-off-by: Miguel Young de la Sota <mcyoung@google.com>
diff --git a/sw/device/lib/dif/BUILD b/sw/device/lib/dif/BUILD
index 2d86875..acf3e79 100644
--- a/sw/device/lib/dif/BUILD
+++ b/sw/device/lib/dif/BUILD
@@ -259,6 +259,7 @@
     ],
     deps = [
         ":base",
+        ":csrng_shared",
         "//hw/ip/edn/data:edn_regs",
         "//sw/device/lib/base:bitfield",
         "//sw/device/lib/base:macros",
diff --git a/sw/device/lib/dif/dif_edn.c b/sw/device/lib/dif/dif_edn.c
index b5849f9..9222f7f 100644
--- a/sw/device/lib/dif/dif_edn.c
+++ b/sw/device/lib/dif/dif_edn.c
@@ -4,15 +4,328 @@
 
 #include "sw/device/lib/dif/dif_edn.h"
 
+#include "sw/device/lib/base/bitfield.h"
+#include "sw/device/lib/base/multibits.h"
+#include "sw/device/lib/dif/dif_csrng_shared.h"
+
 #include "edn_regs.h"  // Generated
 
-OT_WARN_UNUSED_RESULT
-dif_result_t dif_edn_stop(const dif_edn_t *edn) {
+static dif_result_t check_locked(const dif_edn_t *edn) {
+  if (mmio_region_read32(edn->base_addr, EDN_REGWEN_REG_OFFSET) == 0) {
+    return kDifLocked;
+  }
+  return kDifOk;
+}
+
+dif_result_t dif_edn_configure(const dif_edn_t *edn) {
+  if (edn == NULL) {
+    return kDifBadArg;
+  }
+  DIF_RETURN_IF_ERROR(check_locked(edn));
+
+  uint32_t reg = mmio_region_read32(edn->base_addr, EDN_CTRL_REG_OFFSET);
+  reg = bitfield_field32_write(reg, EDN_CTRL_EDN_ENABLE_FIELD,
+                               kMultiBitBool4True);
+  mmio_region_write32(edn->base_addr, EDN_CTRL_REG_OFFSET, reg);
+
+  return kDifOk;
+}
+
+dif_result_t dif_edn_lock(const dif_edn_t *edn) {
+  if (edn == NULL) {
+    return kDifBadArg;
+  }
+  mmio_region_write32(edn->base_addr, EDN_REGWEN_REG_OFFSET, 0);
+  return kDifOk;
+}
+
+dif_result_t dif_edn_is_locked(const dif_edn_t *edn, bool *is_locked) {
+  if (edn == NULL || is_locked == NULL) {
+    return kDifBadArg;
+  }
+  *is_locked = check_locked(edn) != kDifOk;
+  return kDifOk;
+}
+
+dif_result_t dif_edn_set_boot_mode(const dif_edn_t *edn) {
+  if (edn == NULL) {
+    return kDifBadArg;
+  }
+  DIF_RETURN_IF_ERROR(check_locked(edn));
+
+  uint32_t reg = mmio_region_read32(edn->base_addr, EDN_CTRL_REG_OFFSET);
+  reg = bitfield_field32_write(reg, EDN_CTRL_BOOT_REQ_MODE_FIELD,
+                               kMultiBitBool4True);
+  mmio_region_write32(edn->base_addr, EDN_CTRL_REG_OFFSET, reg);
+
+  return kDifOk;
+}
+
+dif_result_t dif_edn_set_auto_mode(const dif_edn_t *edn,
+                                   dif_edn_auto_params_t config) {
+  if (edn == NULL) {
+    return kDifBadArg;
+  }
+  DIF_RETURN_IF_ERROR(check_locked(edn));
+
+  uint32_t reg = mmio_region_read32(edn->base_addr, EDN_CTRL_REG_OFFSET);
+  reg = bitfield_field32_write(reg, EDN_CTRL_CMD_FIFO_RST_FIELD,
+                               kMultiBitBool4True);
+  mmio_region_write32(edn->base_addr, EDN_CTRL_REG_OFFSET, reg);
+
+  for (size_t i = 0; i < config.reseed_material.len; ++i) {
+    mmio_region_write32(edn->base_addr, EDN_RESEED_CMD_REG_OFFSET,
+                        config.reseed_material.data[i]);
+  }
+  for (size_t i = 0; i < config.generate_material.len; ++i) {
+    mmio_region_write32(edn->base_addr, EDN_GENERATE_CMD_REG_OFFSET,
+                        config.generate_material.data[i]);
+  }
+
+  mmio_region_write32(edn->base_addr,
+                      EDN_MAX_NUM_REQS_BETWEEN_RESEEDS_REG_OFFSET,
+                      config.reseed_interval);
+
+  reg = bitfield_field32_write(reg, EDN_CTRL_AUTO_REQ_MODE_FIELD,
+                               kMultiBitBool4True);
+  mmio_region_write32(edn->base_addr, EDN_CTRL_REG_OFFSET, reg);
+
+  return kDifOk;
+}
+
+dif_result_t dif_edn_get_status(const dif_edn_t *edn, dif_edn_status_t flag,
+                                bool *set) {
+  if (edn == NULL || set == NULL) {
+    return kDifBadArg;
+  }
+
+  uint32_t bit;
+  switch (flag) {
+    case kDifEdnStatusReady:
+      bit = EDN_SW_CMD_STS_CMD_RDY_BIT;
+      break;
+    case kDifEdnStatusCsrngAck:
+      bit = EDN_SW_CMD_STS_CMD_STS_BIT;
+      break;
+    default:
+      return kDifBadArg;
+  }
+
+  uint32_t reg = mmio_region_read32(edn->base_addr, EDN_SW_CMD_STS_REG_OFFSET);
+  *set = bitfield_bit32_read(reg, bit);
+  return kDifOk;
+}
+
+dif_result_t dif_edn_get_errors(const dif_edn_t *edn, uint32_t *unhealthy_fifos,
+                                uint32_t *errors) {
+  if (edn == NULL || unhealthy_fifos == NULL || errors == NULL) {
+    return kDifBadArg;
+  }
+  *unhealthy_fifos = 0;
+  *errors = 0;
+
+  uint32_t reg = mmio_region_read32(edn->base_addr, EDN_ERR_CODE_REG_OFFSET);
+  *unhealthy_fifos =
+      bitfield_bit32_copy(*unhealthy_fifos, kDifEdnFifoReseedCmd, reg,
+                          EDN_ERR_CODE_SFIFO_RESCMD_ERR_BIT);
+  *unhealthy_fifos =
+      bitfield_bit32_copy(*unhealthy_fifos, kDifEdnFifoGenerateCmd, reg,
+                          EDN_ERR_CODE_SFIFO_GENCMD_ERR_BIT);
+
+  *errors = bitfield_bit32_copy(*errors, kDifEdnErrorAckSm, reg,
+                                EDN_ERR_CODE_EDN_ACK_SM_ERR_BIT);
+  *errors = bitfield_bit32_copy(*errors, kDifEdnErrorMainSm, reg,
+                                EDN_ERR_CODE_EDN_MAIN_SM_ERR_BIT);
+  *errors = bitfield_bit32_copy(*errors, kDifEdnErrorCounterFault, reg,
+                                EDN_ERR_CODE_EDN_CNTR_ERR_BIT);
+  *errors = bitfield_bit32_copy(*errors, kDifEdnErrorFifoWrite, reg,
+                                EDN_ERR_CODE_FIFO_WRITE_ERR_BIT);
+  *errors = bitfield_bit32_copy(*errors, kDifEdnErrorFifoRead, reg,
+                                EDN_ERR_CODE_FIFO_READ_ERR_BIT);
+  *errors = bitfield_bit32_copy(*errors, kDifEdnErrorFifoFullAndEmpty, reg,
+                                EDN_ERR_CODE_FIFO_STATE_ERR_BIT);
+
+  return kDifOk;
+}
+
+dif_result_t dif_edn_get_cmd_unhealthy_fifo_force(const dif_edn_t *edn,
+                                                  dif_edn_fifo_t fifo) {
   if (edn == NULL) {
     return kDifBadArg;
   }
 
+  uint32_t fifo_bit;
+  switch (fifo) {
+    case kDifEdnFifoReseedCmd:
+      fifo_bit = EDN_ERR_CODE_SFIFO_RESCMD_ERR_BIT;
+      break;
+    case kDifEdnFifoGenerateCmd:
+      fifo_bit = EDN_ERR_CODE_SFIFO_GENCMD_ERR_BIT;
+    default:
+      return kDifBadArg;
+  }
+
+  DIF_RETURN_IF_ERROR(check_locked(edn));
+  mmio_region_write32(edn->base_addr, EDN_ERR_CODE_TEST_REG_OFFSET, fifo_bit);
+  return kDifOk;
+}
+
+dif_result_t dif_edn_get_cmd_error_force(const dif_edn_t *edn,
+                                         dif_edn_error_t error) {
+  if (edn == NULL) {
+    return kDifBadArg;
+  }
+
+  uint32_t error_bit;
+  switch (error) {
+    case kDifEdnErrorAckSm:
+      error_bit = EDN_ERR_CODE_EDN_ACK_SM_ERR_BIT;
+      break;
+    case kDifEdnErrorMainSm:
+      error_bit = EDN_ERR_CODE_EDN_MAIN_SM_ERR_BIT;
+      break;
+    case kDifEdnErrorCounterFault:
+      error_bit = EDN_ERR_CODE_EDN_CNTR_ERR_BIT;
+      break;
+    case kDifEdnErrorFifoWrite:
+      error_bit = EDN_ERR_CODE_FIFO_WRITE_ERR_BIT;
+      break;
+    case kDifEdnErrorFifoRead:
+      error_bit = EDN_ERR_CODE_FIFO_READ_ERR_BIT;
+      break;
+    case kDifEdnErrorFifoFullAndEmpty:
+      error_bit = EDN_ERR_CODE_FIFO_STATE_ERR_BIT;
+      break;
+    default:
+      return kDifBadArg;
+  }
+
+  DIF_RETURN_IF_ERROR(check_locked(edn));
+  mmio_region_write32(edn->base_addr, EDN_ERR_CODE_TEST_REG_OFFSET, error_bit);
+  return kDifOk;
+}
+
+dif_result_t dif_edn_get_main_state_machine(const dif_edn_t *edn,
+                                            uint32_t *state) {
+  if (edn == NULL || state == NULL) {
+    return kDifBadArg;
+  }
+
+  *state = mmio_region_read32(edn->base_addr, EDN_MAIN_SM_STATE_REG_OFFSET);
+  return kDifOk;
+}
+
+dif_result_t dif_edn_instantiate(
+    const dif_edn_t *edn, dif_edn_entropy_src_toggle_t entropy_src_enable,
+    const dif_edn_seed_material_t *seed_material) {
+  if (edn == NULL || seed_material == NULL) {
+    return kDifBadArg;
+  }
+  dif_csrng_seed_material_t seed_material2;
+  memcpy(&seed_material2, seed_material, sizeof(seed_material2));
+  return csrng_send_app_cmd(
+      edn->base_addr, EDN_SW_CMD_REQ_REG_OFFSET,
+      (csrng_app_cmd_t){
+          .id = kCsrngAppCmdInstantiate,
+          .entropy_src_enable =
+              (dif_csrng_entropy_src_toggle_t)entropy_src_enable,
+          .seed_material = &seed_material2,
+      });
+}
+
+dif_result_t dif_edn_reseed(const dif_edn_t *edn,
+                            const dif_edn_seed_material_t *seed_material) {
+  if (edn == NULL || seed_material == NULL) {
+    return kDifBadArg;
+  }
+  dif_csrng_seed_material_t seed_material2;
+  memcpy(&seed_material2, seed_material, sizeof(seed_material2));
+  return csrng_send_app_cmd(edn->base_addr, EDN_SW_CMD_REQ_REG_OFFSET,
+                            (csrng_app_cmd_t){
+                                .id = kCsrngAppCmdReseed,
+                                .seed_material = &seed_material2,
+                            });
+}
+
+dif_result_t dif_edn_update(const dif_edn_t *edn,
+                            const dif_edn_seed_material_t *seed_material) {
+  if (edn == NULL || seed_material == NULL) {
+    return kDifBadArg;
+  }
+  dif_csrng_seed_material_t seed_material2;
+  memcpy(&seed_material2, seed_material, sizeof(seed_material2));
+  return csrng_send_app_cmd(edn->base_addr, EDN_SW_CMD_REQ_REG_OFFSET,
+                            (csrng_app_cmd_t){
+                                .id = kCsrngAppCmdUpdate,
+                                .seed_material = &seed_material2,
+                            });
+}
+
+dif_result_t dif_edn_generate_start(const dif_edn_t *edn, size_t len) {
+  if (edn == NULL || len == 0) {
+    return kDifBadArg;
+  }
+
+  // Round up the number of 128bit blocks. Aligning with respect to uint32_t.
+  // TODO(#6112): Consider using a canonical reference for alignment operations.
+  const uint32_t num_128bit_blocks = (len + 3) / 4;
+  return csrng_send_app_cmd(edn->base_addr, EDN_SW_CMD_REQ_REG_OFFSET,
+                            (csrng_app_cmd_t){
+                                .id = kCsrngAppCmdGenerate,
+                                .generate_len = num_128bit_blocks,
+                            });
+}
+
+dif_result_t dif_edn_uninstantiate(const dif_edn_t *edn) {
+  if (edn == NULL) {
+    return kDifBadArg;
+  }
+  return csrng_send_app_cmd(edn->base_addr, EDN_SW_CMD_REQ_REG_OFFSET,
+                            (csrng_app_cmd_t){
+                                .id = kCsrngAppCmdUnisntantiate,
+                            });
+}
+
+dif_result_t dif_edn_stop(const dif_edn_t *edn) {
+  if (edn == NULL) {
+    return kDifBadArg;
+  }
+  DIF_RETURN_IF_ERROR(check_locked(edn));
+
   mmio_region_write32(edn->base_addr, EDN_CTRL_REG_OFFSET, EDN_CTRL_REG_RESVAL);
 
   return kDifOk;
 }
+
+dif_result_t dif_edn_get_recoverable_alerts(const dif_edn_t *edn,
+                                            uint32_t *alerts) {
+  if (edn == NULL || alerts == NULL) {
+    return kDifBadArg;
+  }
+
+  *alerts = 0;
+  uint32_t reg =
+      mmio_region_read32(edn->base_addr, EDN_RECOV_ALERT_STS_REG_OFFSET);
+  *alerts = bitfield_bit32_copy(*alerts, kDifEdnRecoverableAlertBadEnable, reg,
+                                EDN_RECOV_ALERT_STS_EDN_ENABLE_FIELD_ALERT_BIT);
+  *alerts =
+      bitfield_bit32_copy(*alerts, kDifEdnRecoverableAlertBadBootReqMode, reg,
+                          EDN_RECOV_ALERT_STS_BOOT_REQ_MODE_FIELD_ALERT_BIT);
+  *alerts =
+      bitfield_bit32_copy(*alerts, kDifEdnRecoverableAlertBadAutoReqMode, reg,
+                          EDN_RECOV_ALERT_STS_AUTO_REQ_MODE_FIELD_ALERT_BIT);
+  *alerts =
+      bitfield_bit32_copy(*alerts, kDifEdnRecoverableAlertBadFifoClear, reg,
+                          EDN_RECOV_ALERT_STS_CMD_FIFO_RST_FIELD_ALERT_BIT);
+  *alerts = bitfield_bit32_copy(*alerts, kDifEdnRecoverableAlertRepeatedGenBits,
+                                reg, EDN_RECOV_ALERT_STS_EDN_BUS_CMP_ALERT_BIT);
+  return kDifOk;
+}
+
+dif_result_t dif_edn_clear_recoverable_alerts(const dif_edn_t *edn) {
+  if (edn == NULL) {
+    return kDifBadArg;
+  }
+  mmio_region_write32(edn->base_addr, EDN_RECOV_ALERT_STS_REG_OFFSET, 0);
+  return kDifOk;
+}
diff --git a/sw/device/lib/dif/dif_edn.h b/sw/device/lib/dif/dif_edn.h
index 09354ad..4e06f73 100644
--- a/sw/device/lib/dif/dif_edn.h
+++ b/sw/device/lib/dif/dif_edn.h
@@ -20,25 +20,6 @@
  * - auto refresh: EDN sends reseed and generate commands to the associated
  *   CSRNG instance. The API allows the user to set the CSRNG instantiate,
  *   reseed and generate para meters, as well as the reseed frequency.
- *
- * Common set of operations for both boot-time and auto refresh modes:
- *
- *  - `dif_edn_init()`
- *  - `dif_edn_configure()`
- *
- * Order of operations in boot-time request mode:
- *
- *  - `did_edn_boot_mode_start()`
- *  - `dif_edn_stop()`
- *
- * Order of operations in auto refresh mode:
- *
- *  - `dif_edn_auto_mode_start()`
- *  - `dif_edn_stop()`
- *
- * Remaining work:
- *
- * - Add error status interface.
  */
 
 #include <stdint.h>
@@ -71,7 +52,7 @@
    * reseed the CSRNG. CSRNG will extend the `data` to zeros if the provided
    * value is less than kDifEntropySeedMaterialMaxWordLen.
    */
-  uint32_t len;
+  size_t len;
   /**
    * Seed material used in CSRNG instantiate or generate call.
    */
@@ -83,18 +64,13 @@
  */
 typedef struct dif_edn_auto_params {
   /**
-   * CSRNG instantiate command parameters.
+   * CSRNG reseed command material.
    */
-  dif_edn_seed_material_t instantiate_params;
+  dif_edn_seed_material_t reseed_material;
   /**
-   * CSRNG reseed command parameters.
+   * CSRNG generate command material.
    */
-  dif_edn_seed_material_t reseed_params;
-  /**
-   * Number of uint32_t words to request the CSRNG on each generate call rounded
-   * to the nearest 128bit block.
-   */
-  uint32_t generate_len;
+  dif_edn_seed_material_t generate_material;
   /**
    * Number of generate calls that can be made before a reseed request is made.
    */
@@ -102,61 +78,172 @@
 } dif_edn_auto_params_t;
 
 /**
- * Configures Entropy Distribution Network with runtime information.
+ * EDN Status flags.
+ */
+typedef enum dif_edn_status {
+  /**
+   * Device is ready to receive a command.
+   */
+  kDifEdnStatusReady,
+  /**
+   * Device has recieved an ACK from the CSRNG block.
+   */
+  kDifEdnStatusCsrngAck,
+} dif_edn_status_t;
+
+/**
+ * Enumeration of EDN FIFOs, which indicates which part of the hardware
+ * produced an error.
+ */
+typedef enum dif_edn_fifo {
+  kDifEdnFifoReseedCmd,
+  kDifEdnFifoGenerateCmd,
+} dif_edn_fifo_t;
+
+/**
+ * Enumeration of EDN FIFO errors.
+ */
+typedef enum dif_edn_error {
+  /**
+   * Indicates an error in the command ack state machine.
+   */
+  kDifEdnErrorAckSm,
+  /**
+   * Indicates an error in the main state machine.
+   */
+  kDifEdnErrorMainSm,
+  /**
+   * Indicates an error in a hardened counter.
+   */
+  kDifEdnErrorCounterFault,
+  /**
+   * Indicates a write to a full FIFO occured.
+   */
+  kDifEdnErrorFifoWrite,
+  /**
+   * Indicates a read from an empty FIFO occured.
+   */
+  kDifEdnErrorFifoRead,
+  /**
+   * Indicates a FIFO was somehow both full and empty.
+   */
+  kDifEdnErrorFifoFullAndEmpty,
+} dif_edn_error_t;
+
+/**
+ * CSRNG consume seed from entropy source enable.
+ */
+typedef enum dif_edn_entropy_src_toggle {
+  /**
+   * Seed material used as the only seed material.
+   *
+   * This configuration option will toggle the hardware state of the
+   * CSRNG to non-FIPS compliant until it is re-instantiated.
+   *
+   * Note: Software may opt to XOR the seed material with a seed to implement
+   * a software assisted FIPS mode of operation.
+   */
+  kDifEdnEntropySrcToggleDisable = 1,
+  /**
+   * Entropy source XOR'ed with the provided seed material.
+   */
+  kDifEdnEntropySrcToggleEnable = 0,
+} dif_edn_entropy_src_toggle_t;
+
+/**
+ * Recoverable alerts emitted by the EDN.
+ */
+typedef enum dif_edn_recoverable_alert {
+  /**
+   * Indicates a bad value was written to the EDN_ENABLE field of the control
+   * register.
+   */
+  kDifEdnRecoverableAlertBadEnable,
+  /**
+   * Indicates a bad value was written to the BOOT_REQ_MODE field of the control
+   * register.
+   */
+  kDifEdnRecoverableAlertBadBootReqMode,
+  /**
+   * Indicates a bad value was written to the AUTO_REQ_MODE field of the
+   * control register.
+   */
+  kDifEdnRecoverableAlertBadAutoReqMode,
+  /**
+   * Indicates a bad value was written to the CMD_FIFO_RST field of the
+   * control register.
+   */
+  kDifEdnRecoverableAlertBadFifoClear,
+  /**
+   * Indicates the genbits bus saw two identical values, indicating a possible
+   * attack.
+   */
+  kDifEdnRecoverableAlertRepeatedGenBits,
+} dif_edn_recoverable_alert_t;
+
+/**
+ * Configures EDN with runtime information.
  *
  * This function should need to be called once for the lifetime of `handle`.
  *
- * @param edn An Entropy Distribution Network handle.
+ * @param edn An EDN handle.
  * @return The result of the operation.
  */
 OT_WARN_UNUSED_RESULT
 dif_result_t dif_edn_configure(const dif_edn_t *edn);
 
 /**
- * Enables the Entropy Distribution Network in boot-time mode.
+ * Locks out EDN functionality.
  *
- * Each call to this function should be sequenced with a call to
- * `dif_edn_stop()`.
+ * This function is reentrant: calling it while functionality is locked will
+ * have no effect and return `kDifEdnOk`.
  *
- * @param edn An Entropy Distribution Network handle.
+ * @param edn An EDN handle.
  * @return The result of the operation.
  */
 OT_WARN_UNUSED_RESULT
-dif_result_t dif_edn_boot_mode_start(const dif_edn_t *edn);
+dif_result_t dif_edn_lock(const dif_edn_t *edn);
 
 /**
- * Enables the Entropy Distribution Network in auto refresh mode.
+ * Checks whether this EDN is locked.
+ *
+ * @param edn An EDN handle.
+ * @param[out] is_locked Out-param for the locked state.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_edn_is_locked(const dif_edn_t *edn, bool *is_locked);
+
+/**
+ * Enables the EDN in boot-time mode.
  *
  * Each call to this function should be sequenced with a call to
  * `dif_edn_stop()`.
  *
- * @param edn An Entropy Distribution Network handle.
+ * @param edn An EDN handle.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_edn_set_boot_mode(const dif_edn_t *edn);
+
+/**
+ * Enables the EDN in auto refresh mode.
+ *
+ * Each call to this function should be sequenced with a call to
+ * `dif_edn_stop()`.
+ *
+ * @param edn An EDN handle.
  * @param config Auto request configuration parameters.
  * @return The result of the operation.
  */
 OT_WARN_UNUSED_RESULT
-dif_result_t dif_edn_auto_mode_start(const dif_edn_t *edn,
-                                     dif_edn_auto_params_t *config);
+dif_result_t dif_edn_set_auto_mode(const dif_edn_t *edn,
+                                   dif_edn_auto_params_t config);
 
 /**
- * EDN Status flags.
- */
-typedef enum dif_edn_status {
-  /**
-   * Device is actively processing a command in either auto or boot-time mode of
-   * operation.
-   */
-  kDifEdnStatusCmdRunning,
-  /**
-   * Device has started the boot-time initialization process.
-   */
-  kDifEdnStatusCmdBootInitAck,
-} dif_edn_status_t;
-
-/**
- * Queries the Entropy Distribution Network status flags.
+ * Queries the EDN status flags.
  *
- * @param edn An Entropy Distribution Network handle.
+ * @param edn An EDN handle.
  * @param flag Status flag to query.
  * @param set Flag state (set/unset).
  * @return The result of the operation.
@@ -165,35 +252,165 @@
                                 bool *set);
 
 /**
+ * Queries the EDN error flags.
+ *
+ * @param edn An EDN handle.
+ * @param unhealthy_fifos Bitset of FIFOs in an unhealthy state; indices are
+ * `dif_edn_fifo_t`.
+ * @param errors Bitset of errors relating to the above FIFOs; indices are
+ * `dif_edn_error_t`.
+ * @return The result of the operation.
+ */
+dif_result_t dif_edn_get_errors(const dif_edn_t *edn, uint32_t *unhealthy_fifos,
+                                uint32_t *errors);
+
+/**
+ * Forces the status registers to indicate `fifo` as being in an unhealthy
+ * state.
+ *
+ * @param edn An EDN handle
+ * @param fifo The FIFO to mark as unhealthy.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_edn_get_cmd_unhealthy_fifo_force(const dif_edn_t *edn,
+                                                  dif_edn_fifo_t fifo);
+
+/**
+ * Forces the status registers to indicate a particular error cause.
+ *
+ * @param edn An EDN handle
+ * @param error The error to force.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_edn_get_cmd_error_force(const dif_edn_t *edn,
+                                         dif_edn_error_t error);
+
+/**
+ * Returns an opaque blob indicating the main state machine's current state.
+ *
+ * @param csrng An EDN handle
+ * @param state[out] The state machine state as an opaque blob.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_edn_get_main_state_machine(const dif_edn_t *edn,
+                                            uint32_t *state);
+
+/**
+ * Initializes CSRNG instance with a new seed value.
+ *
+ * `seed_material` is used as specified in NIST SP 800-90Ar1 section
+ * 10.2.1.3.1.
+ *
+ * `seed_material` can be NULL, in which case CSRNG will use a zero
+ * vector instead.
+ *
+ * @param edn An EDN handle.
+ * @param entropy_src_enable Entropy source input enable.
+ * @param seed_material Seed initialization parameters.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_edn_instantiate(
+    const dif_edn_t *edn, dif_edn_entropy_src_toggle_t entropy_src_enable,
+    const dif_edn_seed_material_t *seed_material);
+
+/**
+ * Reseeds CSRNG instance.
+ *
+ * When `seed_material.seed_material_len` is set to 0, only the entropy source
+ * seed is used to reseed the instance, otherwise it will be XOR'ed with the
+ * entropy source.
+ *
+ * @param edn An EDN handle.
+ * @param seed_material Reseed parameters.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_edn_reseed(const dif_edn_t *edn,
+                            const dif_edn_seed_material_t *seed_material);
+
+/**
+ * Updates CSRNG state.
+ *
+ * This function is similar to `dif_edn_reseed()`, except:
+ *
+ * - Only `seed_material.seed_material` is used in the update operation.
+ * - The update operation does not reset the internal CSRNG reseed
+ *   counter.
+ *
+ * @param edn An EDN handle.
+ * @param seed_material Update parameters.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_edn_update(const dif_edn_t *edn,
+                            const dif_edn_seed_material_t *seed_material);
+
+/**
+ * Requests cryptographic entropy bits from the CSRNG.
+ *
+ * The prediction resistance flag as specified in SP 800-90Ar1 section
+ * 10.2.1.1 is not directly supported by the hardware. It is the
+ * responsibility of the caller to reseed as needed before calling
+ * this function.
+ *
+ * The CSRNG accepts generation requests with 128-bit granularity, with
+ * a minimum 128-bit request size. This function will increase the size
+ * of the request to align it to the nearest 128-bit boundary.
+ *
+ * @param edn An EDN handle.
+ * @param len Number of uint32_t words to generate.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_edn_generate_start(const dif_edn_t *edn, size_t len);
+
+/**
+ * Uninstantiates CSRNG.
+ *
+ * Resets the CSRNG instance. Values in the CSRNG are zeroed out. This
+ * command effectively resets the CSRNG, clearing any errors that it
+ * may have encountered due to processing or entropy source errors.
+ *
+ * @param edn An EDN handle.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_edn_uninstantiate(const dif_edn_t *edn);
+
+/**
  * Stops the current mode of operation and disables the entropy module.
  *
- * @param edn An Entropy Distribution Network handle.
+ * @param edn An EDN handle.
  * @return The result of the operation.
  */
 OT_WARN_UNUSED_RESULT
 dif_result_t dif_edn_stop(const dif_edn_t *edn);
 
 /**
- * Locks out Entropy Distribution Network functionality.
+ * Gets the recoverable alerts currently recorded in the EDN block.
  *
- * This function is reentrant: calling it while functionality is locked will
- * have no effect and return `kDifEdnOk`.
+ * This function returns the alerts in a bitset whose indices are given by
+ * `dif_edn_recoverable_alert_t`.
  *
- * @param edn An Entropy Distribution Network handle.
+ * @param edn An EDN handle.
+ * @param[out] alerts Bitset of alerts currently recorded.
  * @return The result of the operation.
  */
 OT_WARN_UNUSED_RESULT
-dif_result_t dif_edn_lock(const dif_edn_t *edn);
+dif_result_t dif_edn_get_recoverable_alerts(const dif_edn_t *edn,
+                                            uint32_t *alerts);
 
 /**
- * Checks whether this Entropy Distribution Network is locked.
+ * Clears all recoverable alerts currently recorded in the EDN block.
  *
- * @param edn An Entropy Distribution Network handle.
- * @param[out] is_locked Out-param for the locked state.
+ * @param edn An EDN handle.
  * @return The result of the operation.
  */
 OT_WARN_UNUSED_RESULT
-dif_result_t dif_edn_is_locked(const dif_edn_t *edn, bool *is_locked);
+dif_result_t dif_edn_clear_recoverable_alerts(const dif_edn_t *edn);
 
 #ifdef __cplusplus
 }  // extern "C"