[dif_sram_ctrl] Add missing implementation

This change adds `dif_sram_ctrl_scramble` implementation and
unittests.

This function constitutes the recommended way of completely scrambling
the SRAM. The function is blocking, the alternative way of
constructing a non-blocking version is described in the description.

`dif_sram_ctrl_scramble_is_busy` has been removed from the header file,
as there is no real need for it, the status can be queried through
`dif_sram_ctrl_get_status`.

`dif_sram_ctrl_wipe` is implemented in #10490 .

Signed-off-by: Silvestrs Timofejevs <silvestrst@lowrisc.org>
diff --git a/sw/device/lib/dif/dif_sram_ctrl.c b/sw/device/lib/dif/dif_sram_ctrl.c
index fa8914f..46a4a7b 100644
--- a/sw/device/lib/dif/dif_sram_ctrl.c
+++ b/sw/device/lib/dif/dif_sram_ctrl.c
@@ -64,6 +64,39 @@
   return mmio_region_read32(sram_ctrl->base_addr, SRAM_CTRL_STATUS_REG_OFFSET);
 }
 
+dif_result_t dif_sram_ctrl_scramble(const dif_sram_ctrl_t *sram_ctrl) {
+  if (sram_ctrl == NULL) {
+    return kDifBadArg;
+  }
+
+  if (sram_ctrl_locked_ctrl(sram_ctrl)) {
+    return kDifLocked;
+  }
+
+  // Issue request for new scrambling key.
+  uint32_t reg =
+      bitfield_bit32_write(0, SRAM_CTRL_CTRL_RENEW_SCR_KEY_BIT, true);
+  mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_CTRL_REG_OFFSET, reg);
+
+  // Wait until the scrambling key has been updated.
+  dif_sram_ctrl_status_bitfield_t status;
+  do {
+    status = sram_ctrl_get_status(sram_ctrl);
+  } while ((status & kDifSramCtrlStatusScrKeyValid) == 0);
+
+  // Overwrite memory with pseudo random data.
+  reg = bitfield_bit32_write(0, SRAM_CTRL_CTRL_INIT_BIT, true);
+  mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_CTRL_REG_OFFSET, reg);
+
+  // Wait for memory to be overwritten with pseudo random data.
+  do {
+    status = sram_ctrl_get_status(sram_ctrl);
+  } while ((status & kDifSramCtrlStatusInitDone) == 0);
+
+  // Check for the errors during memory overwriting.
+  return (status & kDifSramCtrlStatusInitErr) == 0 ? kDifOk : kDifError;
+}
+
 dif_result_t dif_sram_ctrl_request_new_key(const dif_sram_ctrl_t *sram_ctrl) {
   if (sram_ctrl == NULL) {
     return kDifBadArg;
diff --git a/sw/device/lib/dif/dif_sram_ctrl.h b/sw/device/lib/dif/dif_sram_ctrl.h
index 8fe221f..9bfdb9f 100644
--- a/sw/device/lib/dif/dif_sram_ctrl.h
+++ b/sw/device/lib/dif/dif_sram_ctrl.h
@@ -94,7 +94,7 @@
 } dif_sram_ctrl_lock_t;
 
 /**
- * Performs SRAM scrambling.
+ * Performs blocking SRAM scrambling operation.
  *
  * This function should only be called when the data is no longer used.
  *
@@ -107,13 +107,10 @@
  * values or predictable data that could potentially make "unscrambling"
  * easier.
  *
- * This operation is expected to take a significant amount of CPU cycles. The
- * status can be checked via `dif_sram_ctrl_scramble_is_busy`, which is useful
- * when a non-blocking work flow is desirable. Otherwise any SRAM access will
- * automatically block until this operation has finished.
- *
- * The equivalent effect can be achieved by calling
- * `dif_sram_ctrl_request_new_key`, followed by `dif_sram_ctrl_wipe`.
+ * This operation is expected to take a significant amount of CPU cycles. If
+ * a non-blocking alternative is required, then `dif_sram_ctrl_request_new_key`,
+ * should be used followed by `dif_sram_ctrl_wipe`. The status of these
+ * operations can be found through `dif_sram_ctrl_get_status`.
  *
  * Note: when dealing with the Main RAM, additional implication is that the
  *       C runtime can be invalidated by the call to this function, and must be
@@ -126,19 +123,6 @@
 dif_result_t dif_sram_ctrl_scramble(const dif_sram_ctrl_t *sram_ctrl);
 
 /**
- * Checks whether SRAM scramble is still progress.
- *
- * Useful when a non-blocking work flow is desirable.
- *
- * @param sram_ctrl A SRAM Controller handle.
- * @param[out] is_busy Out-param for the busy state.
- * @return The result of the operation.
- */
-OT_WARN_UNUSED_RESULT
-dif_result_t dif_sram_ctrl_scramble_is_busy(const dif_sram_ctrl_t *sram_ctrl,
-                                            bool *is_busy);
-
-/**
  * Requests a new scrambling key.
  *
  * This function should only be called when the data is no longer used.
diff --git a/sw/device/lib/dif/dif_sram_ctrl_unittest.cc b/sw/device/lib/dif/dif_sram_ctrl_unittest.cc
index b503d20..34a050d 100644
--- a/sw/device/lib/dif/dif_sram_ctrl_unittest.cc
+++ b/sw/device/lib/dif/dif_sram_ctrl_unittest.cc
@@ -23,6 +23,60 @@
   dif_sram_ctrl_t sram_ctrl_ = {.base_addr = dev().region()};
 };
 
+class Scramble : public SramCtrlTest {};
+
+TEST_F(Scramble, NullArgs) {
+  EXPECT_EQ(dif_sram_ctrl_scramble(nullptr), kDifBadArg);
+}
+
+TEST_F(Scramble, Locked) {
+  EXPECT_READ32(SRAM_CTRL_CTRL_REGWEN_REG_OFFSET, 0);
+  EXPECT_EQ(dif_sram_ctrl_scramble(&sram_ctrl_), kDifLocked);
+}
+
+TEST_F(Scramble, Failure) {
+  EXPECT_READ32(SRAM_CTRL_CTRL_REGWEN_REG_OFFSET, 1);
+
+  // Issue request for new scrambling key.
+  EXPECT_WRITE32(SRAM_CTRL_CTRL_REG_OFFSET,
+                 {{SRAM_CTRL_CTRL_RENEW_SCR_KEY_BIT, true},
+                  {SRAM_CTRL_CTRL_INIT_BIT, false}});
+  EXPECT_READ32(SRAM_CTRL_STATUS_REG_OFFSET, kDifSramCtrlStatusScrKeyValid);
+
+  // Overwrite memory with pseudo random data.
+  EXPECT_WRITE32(SRAM_CTRL_CTRL_REG_OFFSET,
+                 {{SRAM_CTRL_CTRL_RENEW_SCR_KEY_BIT, false},
+                  {SRAM_CTRL_CTRL_INIT_BIT, true}});
+  EXPECT_READ32(SRAM_CTRL_STATUS_REG_OFFSET,
+                std::numeric_limits<uint32_t>::max());
+
+  EXPECT_EQ(dif_sram_ctrl_scramble(&sram_ctrl_), kDifError);
+}
+
+TEST_F(Scramble, Success) {
+  EXPECT_READ32(SRAM_CTRL_CTRL_REGWEN_REG_OFFSET, 1);
+
+  // Issue request for new scrambling key, and emulate three iteration status
+  // read loop.
+  EXPECT_WRITE32(SRAM_CTRL_CTRL_REG_OFFSET,
+                 {{SRAM_CTRL_CTRL_RENEW_SCR_KEY_BIT, true},
+                  {SRAM_CTRL_CTRL_INIT_BIT, false}});
+  EXPECT_READ32(SRAM_CTRL_STATUS_REG_OFFSET, 0);
+  EXPECT_READ32(SRAM_CTRL_STATUS_REG_OFFSET, 0);
+  EXPECT_READ32(SRAM_CTRL_STATUS_REG_OFFSET, kDifSramCtrlStatusScrKeyValid);
+
+  // Overwrite memory with pseudo random data, and emulate three iteration
+  // status read loop.
+  EXPECT_WRITE32(SRAM_CTRL_CTRL_REG_OFFSET,
+                 {{SRAM_CTRL_CTRL_RENEW_SCR_KEY_BIT, false},
+                  {SRAM_CTRL_CTRL_INIT_BIT, true}});
+  EXPECT_READ32(SRAM_CTRL_STATUS_REG_OFFSET, 0);
+  EXPECT_READ32(SRAM_CTRL_STATUS_REG_OFFSET, 0);
+  EXPECT_READ32(SRAM_CTRL_STATUS_REG_OFFSET, kDifSramCtrlStatusInitDone);
+
+  EXPECT_EQ(dif_sram_ctrl_scramble(&sram_ctrl_), kDifOk);
+}
+
 class RequestNewKeyTest : public SramCtrlTest {};
 
 TEST_F(RequestNewKeyTest, NullArgs) {