[lc_ctrl/dif] Add get/set functions for OTP test register

Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/sw/device/lib/dif/dif_lc_ctrl.c b/sw/device/lib/dif/dif_lc_ctrl.c
index df5986b..f6d08b5 100644
--- a/sw/device/lib/dif/dif_lc_ctrl.c
+++ b/sw/device/lib/dif/dif_lc_ctrl.c
@@ -314,3 +314,35 @@
                       1);
   return kDifLcCtrlMutexOk;
 }
+
+dif_lc_ctrl_mutex_result_t dif_lc_ctrl_set_otp_test_reg(const dif_lc_ctrl_t *lc,
+                                                        uint32_t settings) {
+  if (lc == NULL) {
+    return kDifLcCtrlMutexBadArg;
+  }
+
+  uint32_t busy = mmio_region_read32(lc->params.base_addr,
+                                     LC_CTRL_TRANSITION_REGWEN_REG_OFFSET);
+  if (busy == 0) {
+    return kDifLcCtrlMutexAlreadyTaken;
+  }
+
+  mmio_region_write32(lc->params.base_addr, LC_CTRL_OTP_TEST_CTRL_REG_OFFSET,
+                      settings);
+
+  return kDifLcCtrlMutexOk;
+}
+
+dif_lc_ctrl_result_t dif_lc_ctrl_get_otp_test_reg(const dif_lc_ctrl_t *lc,
+                                                  uint32_t *settings) {
+  if (lc == NULL || settings == NULL) {
+    return kDifLcCtrlBadArg;
+  }
+
+  uint32_t reg = mmio_region_read32(lc->params.base_addr,
+                                    LC_CTRL_OTP_TEST_CTRL_REG_OFFSET);
+
+  *settings = bitfield_field32_read(reg, LC_CTRL_OTP_TEST_CTRL_VAL_FIELD);
+
+  return kDifLcCtrlOk;
+}
diff --git a/sw/device/lib/dif/dif_lc_ctrl.h b/sw/device/lib/dif/dif_lc_ctrl.h
index 39c4d9c..b53f254 100644
--- a/sw/device/lib/dif/dif_lc_ctrl.h
+++ b/sw/device/lib/dif/dif_lc_ctrl.h
@@ -425,6 +425,28 @@
     const dif_lc_ctrl_t *lc, dif_lc_ctrl_state_t state,
     const dif_lc_ctrl_token_t *token);
 
+/**
+ * Writes settings to the vendor-specific OTP test control register.
+ *
+ * @param lc A lifecycle handle.
+ * @param settings The settings to write to the register.
+ * @return The result of the operation.
+ */
+DIF_WARN_UNUSED_RESULT
+dif_lc_ctrl_mutex_result_t dif_lc_ctrl_set_otp_test_reg(const dif_lc_ctrl_t *lc,
+                                                        uint32_t settings);
+
+/**
+ * Reads settings from the vendor-specific OTP test control register.
+ *
+ * @param lc A lifecycle handle.
+ * @param settings Output parameter for the settings.
+ * @return The result of the operation.
+ */
+DIF_WARN_UNUSED_RESULT
+dif_lc_ctrl_result_t dif_lc_ctrl_get_otp_test_reg(const dif_lc_ctrl_t *lc,
+                                                  uint32_t *settings);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif  // __cplusplus
diff --git a/sw/device/lib/dif/dif_lc_ctrl_unittest.cc b/sw/device/lib/dif/dif_lc_ctrl_unittest.cc
index df02b83..610ebbe 100644
--- a/sw/device/lib/dif/dif_lc_ctrl_unittest.cc
+++ b/sw/device/lib/dif/dif_lc_ctrl_unittest.cc
@@ -226,5 +226,20 @@
   EXPECT_EQ(dif_lc_ctrl_transition(nullptr, kDifLcCtrlStateProd, &token),
             kDifLcCtrlMutexBadArg);
 }
+
+class OtpTestRegTest : public LcTest {};
+
+TEST_F(OtpTestRegTest, Read) {
+  uint32_t settings_read = 0;
+  EXPECT_READ32(LC_CTRL_OTP_TEST_CTRL_REG_OFFSET, 0x5A);
+  EXPECT_EQ(dif_lc_ctrl_get_otp_test_reg(&lc_, &settings_read), kDifLcCtrlOk);
+  EXPECT_EQ(settings_read, 0x5A);
+}
+
+TEST_F(OtpTestRegTest, Write) {
+  EXPECT_READ32(LC_CTRL_TRANSITION_REGWEN_REG_OFFSET, true);
+  EXPECT_WRITE32(LC_CTRL_OTP_TEST_CTRL_REG_OFFSET, 0xA5);
+  EXPECT_EQ(dif_lc_ctrl_set_otp_test_reg(&lc_, 0xA5), kDifLcCtrlMutexOk);
+}
 }  // namespace
 }  // namespace dif_lc_ctrl_unittest