CC3XX: Add a stateless API to read the TRNG

This stateless API can be used also in places where global
variables are not setup yet, i.e. in pre-main. The function
does not retain any state or config that might have changed
during its execution. It does not bypass HW tests.

Signed-off-by: Antonio de Angelis <antonio.deangelis@arm.com>
Change-Id: Ic7d4043c77b3dac6f21da87fc252d1210b0faaa7
diff --git a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_trng.h b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_trng.h
index b9fb87e..1aca5b8 100644
--- a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_trng.h
+++ b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_trng.h
@@ -57,7 +57,7 @@
 void cc3xx_lowlevel_trng_sp800_90b_mode(bool enable);
 
 /**
- * @brief                       Sets the configuration (ROSC_ID, subsampling rate) for
+ * @brief                       Sets the global configuration (ROSC_ID, subsampling rate) for
  *                              the usage of the TRNG by the other APIs used by this
  *                              module. If this is not called, default parameters
  *                              defined at build time will be used, i.e.
@@ -75,7 +75,7 @@
 cc3xx_err_t cc3xx_lowlevel_trng_set_config(enum cc3xx_rng_rosc_id_t rosc_id, uint32_t subsampling_rate);
 
 /**
- * @brief                       Validates the configuration of the TRNG
+ * @brief                       Validates the global configuration of the TRNG
  *
  * @return cc3xx_err_t          CC3XX_ERR_SUCCESS on success, or CC3XX_ERR_RNG_INVALID_TRNG_CONFIG if
  *                              an invalid configuration is detected
@@ -84,7 +84,7 @@
 
 /**
  * @brief                       Sets the TRNG_DEBUG_CONTROL register to bypass mode for the
- *                              respective HW tests
+ *                              respective HW tests, in the global configuration (state) structure
  *
  * @param[in] bypass_autocorr   Set to \a true to bypass the AUTOCORR test
  * @param[in] bypass_crngt      Set to \a true to bypass the CRNGT test
@@ -94,13 +94,39 @@
 void cc3xx_lowlevel_trng_set_hw_test_bypass(bool bypass_autocorr, bool bypass_crngt, bool bypass_vnc);
 
 /**
- * @brief                       Reads the sample out of the TRNG
+ * @brief                       Reads the sample out of the TRNG, without accessing the global config state
  *
- * @param[out] buf              Output buffer, word aligned, into which the entropy is read
+ * @param[out] buf              Output buffer, word aligned, into which the sample is read
  * @param[in]  word_count       Size in words of the \p buf output buffer, must be equal to
  *                              the number of words of P_CC3XX->rng.ehr_data, i.e. CC3XX_TRNG_SAMPLE_SIZE
  *                              when expressed in bytes
  *
+ * @note                        If the ROSC ID or the subsampling rate get bumped during a reading, the new
+ *                              values won't be saved in the global config. This function does not access
+ *                              any global config or state so it is safe to use when globals are not set up.
+ *                              HW tests are not bypassed when this function is used
+ *
+ * @note                        This is a one-shot function, unlike the \a cc3xx_lowlevel_trng_get_sample
+ *                              which requires separate calls to \a cc3xx_lowlevel_trng_init first, and
+ *                              \a cc3xx_lowlevel_trng_finish afterwards
+ *
+ * @return cc3xx_err_t          CC3XX_ERR_SUCCESS on success, CC3XX_ERR_RNG_TOO_MANY_ATTEMPTS in
+ *                              case errors have been detected on each generation. The maximum
+ *                              number of generations is controlled by CC3XX_CONFIG_RNG_MAX_ATTEMPTS
+ */
+cc3xx_err_t cc3xx_lowlevel_trng_get_sample_stateless(uint32_t *buf, size_t word_count);
+
+/**
+ * @brief                       Reads the sample out of the TRNG
+ *
+ * @param[out] buf              Output buffer, word aligned, into which the sample is read
+ * @param[in]  word_count       Size in words of the \p buf output buffer, must be equal to
+ *                              the number of words of P_CC3XX->rng.ehr_data, i.e. CC3XX_TRNG_SAMPLE_SIZE
+ *                              when expressed in bytes
+ *
+ * @note                        This function might alter the global config (state) hence it requires global
+ *                              variables to be available
+ *
  * @return cc3xx_err_t          CC3XX_ERR_SUCCESS on success, CC3XX_ERR_RNG_TOO_MANY_ATTEMPTS in
  *                              case errors have been detected on each generation. The maximum
  *                              number of generations is controlled by CC3XX_CONFIG_RNG_MAX_ATTEMPTS
@@ -108,7 +134,7 @@
 cc3xx_err_t cc3xx_lowlevel_trng_get_sample(uint32_t *buf, size_t word_count);
 
 /**
- * @brief                       Initialises the TRNG before a call to \a cc3xx_lowlevel_trng_get_entropy
+ * @brief                       Initialises the TRNG before a call to \a cc3xx_lowlevel_trng_get_sample
  *
  * @return cc3xx_err_t          CC3XX_ERR_SUCCESS
  */
diff --git a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_trng.c b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_trng.c
index 8766e06..9b22711 100644
--- a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_trng.c
+++ b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_trng.c
@@ -100,47 +100,42 @@
     P_CC3XX->rng.rng_clk_enable = 0x0U;
 }
 
-static inline void trng_double_subsampling_rate(void)
+static inline uint32_t trng_double_subsampling_rate(uint32_t subsampling_rate)
 {
-    uint64_t product = (uint64_t)g_trng_config.rosc.subsampling_rate * 2ULL;
+    const uint64_t product = ((uint64_t)subsampling_rate) * 2ULL;
 
-    g_trng_config.rosc.subsampling_rate =
-        (product > UINT32_MAX) ? UINT32_MAX : (uint32_t)product;
+    return (product > UINT32_MAX) ? UINT32_MAX : (uint32_t)product;
 }
 
-static void trng_bump_rosc_id_and_subsampling_rate(void)
+static void trng_bump_rosc_id_and_subsampling_rate(bool stateless)
 {
-    if (g_trng_config.rosc.id == CC3XX_RNG_ROSC_ID_3 &&
-        g_trng_config.rosc.subsampling_rate == UINT32_MAX) {
+    uint32_t rosc_id = P_CC3XX->rng.trng_config & 0b11;
+    uint32_t rosc_subsampling_rate = P_CC3XX->rng.sample_cnt1;
+
+    if ((rosc_id == CC3XX_RNG_ROSC_ID_3) && (rosc_subsampling_rate == UINT32_MAX)) {
         /* Cannot bump further */
         return;
     }
 
-    if (g_trng_config.rosc.id < CC3XX_RNG_ROSC_ID_3) {
+    if (rosc_id < CC3XX_RNG_ROSC_ID_3) {
         /* For each subsampling rate, bump the rosc id */
-        g_trng_config.rosc.id++;
+        rosc_id++;
     } else {
         /* Double the subsampling rate when rosc id is at its max*/
-        g_trng_config.rosc.id = CC3XX_RNG_ROSC_ID_0;
-        trng_double_subsampling_rate();
+        rosc_id = CC3XX_RNG_ROSC_ID_0;
+        rosc_subsampling_rate = trng_double_subsampling_rate(rosc_subsampling_rate);
+    }
+
+    P_CC3XX->rng.trng_config = rosc_id | (0x1U << 2);
+    P_CC3XX->rng.sample_cnt1 = rosc_subsampling_rate;
+
+    if (!stateless) {
+        g_trng_config.rosc.id = rosc_id;
+        g_trng_config.rosc.subsampling_rate = rosc_subsampling_rate;
     }
 }
 
-cc3xx_err_t cc3xx_lowlevel_trng_init(void)
-{
-    trng_init(g_trng_config.rosc.id, g_trng_config.rosc.subsampling_rate, g_trng_config.debug_control);
-
-    return CC3XX_ERR_SUCCESS;
-}
-
-cc3xx_err_t cc3xx_lowlevel_trng_finish(void)
-{
-    trng_finish();
-
-    return CC3XX_ERR_SUCCESS;
-}
-
-cc3xx_err_t cc3xx_lowlevel_trng_get_sample(uint32_t *buf, size_t word_count)
+static cc3xx_err_t trng_get_sample(uint32_t *buf, size_t word_count, bool stateless)
 {
     uint32_t attempt_count = 0;
     uint32_t idx;
@@ -165,18 +160,21 @@
             P_CC3XX->rng.rng_icr = 0x3FU;
 
             /* Bump the rosc id and subsampling rate */
-            trng_bump_rosc_id_and_subsampling_rate();
+            trng_bump_rosc_id_and_subsampling_rate(stateless);
 
             /* Restart TRNG */
-            cc3xx_lowlevel_trng_init();
+            trng_init(
+                P_CC3XX->rng.trng_config & 0b11,
+                P_CC3XX->rng.sample_cnt1,
+                P_CC3XX->rng.trng_debug_control);
 
             attempt_count++;
         }
-    } while ((! (P_CC3XX->rng.rng_isr & 0x1U))
-             && attempt_count < CC3XX_CONFIG_RNG_MAX_ATTEMPTS);
+    } while ((!(P_CC3XX->rng.rng_isr & 0x1U))
+             && (attempt_count < CC3XX_CONFIG_RNG_MAX_ATTEMPTS));
 
     if (attempt_count == CC3XX_CONFIG_RNG_MAX_ATTEMPTS) {
-        cc3xx_lowlevel_trng_finish();
+        trng_finish();
         FATAL_ERR(CC3XX_ERR_RNG_TOO_MANY_ATTEMPTS);
         return CC3XX_ERR_RNG_TOO_MANY_ATTEMPTS;
     }
@@ -197,6 +195,51 @@
     return CC3XX_ERR_SUCCESS;
 }
 
+/*!
+ * \defgroup cc3xx_trng Set of functions implementing the API to access the TRNG
+ *                      for reading random bits
+ *
+ */
+/*!@{*/
+cc3xx_err_t cc3xx_lowlevel_trng_init(void)
+{
+    trng_init(g_trng_config.rosc.id, g_trng_config.rosc.subsampling_rate, g_trng_config.debug_control);
+
+    return CC3XX_ERR_SUCCESS;
+}
+
+cc3xx_err_t cc3xx_lowlevel_trng_finish(void)
+{
+    trng_finish();
+
+    return CC3XX_ERR_SUCCESS;
+}
+
+cc3xx_err_t cc3xx_lowlevel_trng_get_sample_stateless(uint32_t *buf, size_t word_count)
+{
+    cc3xx_err_t err;
+    const bool stateless = true;
+
+    /* In stateless mode do not set any TRNG test bypass */
+    trng_init(CC3XX_CONFIG_RNG_RING_OSCILLATOR_ID, CC3XX_CONFIG_RNG_SUBSAMPLING_RATE, 0x0);
+    err = trng_get_sample(buf, word_count, stateless);
+    if (err != CC3XX_ERR_SUCCESS) {
+        return err;
+    }
+    trng_finish();
+
+    return err;
+}
+
+cc3xx_err_t cc3xx_lowlevel_trng_get_sample(uint32_t *buf, size_t word_count)
+{
+    const bool stateless = false;
+    /* Unless called from the _stateless APIs, the get_sample will update
+     * the global config of the TRNG, i.e. to retain state for future calls
+     */
+    return trng_get_sample(buf, word_count, stateless);
+}
+
 cc3xx_err_t cc3xx_lowlevel_trng_set_config(
     enum cc3xx_rng_rosc_id_t rosc_id,
     uint32_t subsampling_rate)
@@ -253,4 +296,5 @@
 
     g_trng_config.debug_control = hw_entropy_tests_control;
 }
+/*!@}*/
 #endif /* !CC3XX_CONFIG_RNG_EXTERNAL_TRNG */