feat(mt8186): add common and MT8186 TRNG driver
Introduce a common RNG driver along with the specific driver for MT8186
platform.
Change-Id: I9f4437b6a4b3e8564a035ff5abb681bcfe85bd1e
diff --git a/plat/mediatek/drivers/rng/mt8186/rng_plat.c b/plat/mediatek/drivers/rng/mt8186/rng_plat.c
new file mode 100644
index 0000000..691b923
--- /dev/null
+++ b/plat/mediatek/drivers/rng/mt8186/rng_plat.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/smccc.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <services/trng_svc.h>
+#include <smccc_helpers.h>
+
+#include <mtk_mmap_pool.h>
+#include <mtk_sip_svc.h>
+#include "rng_plat.h"
+
+static spinlock_t rng_lock;
+
+static int trng_wait(uint32_t reg, uint32_t expected_value)
+{
+ uint64_t timeout = timeout_init_us(TRNG_TIME_OUT);
+ uint32_t value = 0;
+
+ do {
+ value = mmio_read_32(reg);
+ if ((value & expected_value) == expected_value)
+ return 0;
+
+ udelay(10);
+ } while (!timeout_elapsed(timeout));
+
+ return -ETIMEDOUT;
+}
+
+static int trng_write(uint32_t reg, uint32_t value,
+ uint32_t read_reg, uint32_t expected_value)
+{
+ int retry = MTK_TRNG_MAX_ROUND;
+ uint32_t read_value = 0;
+
+ do {
+ mmio_write_32(reg, value);
+
+ read_value = mmio_read_32(read_reg);
+ if ((read_value & value) == expected_value)
+ return 0;
+
+ udelay(10);
+ } while (--retry > 0);
+
+ return -ETIMEDOUT;
+}
+
+static uint32_t trng_prng(uint32_t *rand)
+{
+ int32_t ret = 0;
+ uint32_t seed[4] = {0};
+
+ if (rand == NULL)
+ return MTK_SIP_E_INVALID_PARAM;
+
+ /* ungate */
+ ret = trng_write(TRNG_PDN_CLR, TRNG_PDN_VALUE, TRNG_PDN_STATUS, 0);
+ if (ret) {
+ ERROR("%s: ungate fail\n", __func__);
+ return MTK_SIP_E_NOT_SUPPORTED;
+ }
+
+ /* read random data once and drop it */
+ seed[0] = mmio_read_32(TRNG_DATA);
+
+ /* enable von-neumann extractor */
+ mmio_setbits_32(TRNG_CONF, TRNG_CONF_VON_EN);
+
+ /* start */
+ mmio_setbits_32(TRNG_CTRL, TRNG_CTRL_START);
+
+ /* get seeds from trng */
+ for (int i = 0; i < ARRAY_SIZE(seed); i++) {
+ ret = trng_wait(TRNG_CTRL, TRNG_CTRL_RDY);
+ if (ret) {
+ ERROR("%s: trng NOT ready\n", __func__);
+ return MTK_SIP_E_NOT_SUPPORTED;
+ }
+
+ seed[i] = mmio_read_32(TRNG_DATA);
+ }
+
+ /* stop */
+ mmio_clrbits_32(TRNG_CTRL, TRNG_CTRL_START);
+
+ /* gate */
+ ret = trng_write(TRNG_PDN_SET, TRNG_PDN_VALUE, TRNG_PDN_STATUS, TRNG_PDN_VALUE);
+ if (ret) {
+ ERROR("%s: gate fail\n", __func__);
+ return MTK_SIP_E_NOT_SUPPORTED;
+ }
+
+ for (int i = 0; i < ARRAY_SIZE(seed); i++)
+ rand[i] = seed[i];
+
+ return 0;
+}
+
+static uint32_t get_true_rnd(uint32_t *val, uint32_t num)
+{
+ uint32_t rand[4] = {0};
+ uint32_t ret;
+
+ if (val == NULL || num > ARRAY_SIZE(rand))
+ return MTK_SIP_E_INVALID_PARAM;
+
+ spin_lock(&rng_lock);
+ ret = trng_prng(rand);
+ spin_unlock(&rng_lock);
+
+ for (int i = 0; i < num; i++)
+ val[i] = rand[i];
+
+ return ret;
+}
+
+/*
+ * plat_get_entropy - get 64-bit random number data which is used form
+ * atf early stage
+ * output - out: output 64-bit entropy combine with 2 32-bit random number
+ */
+bool plat_get_entropy(uint64_t *out)
+{
+ uint32_t entropy_pool[2] = {0};
+ uint32_t ret;
+
+ assert(out);
+ assert(!check_uptr_overflow((uintptr_t)out, sizeof(*out)));
+
+ /* Get 2 32-bits entropy */
+ ret = get_true_rnd(entropy_pool, ARRAY_SIZE(entropy_pool));
+ if (ret)
+ return false;
+
+ /* Output 8 bytes entropy combine with 2 32-bit random number. */
+ *out = ((uint64_t)entropy_pool[0] << 32) | entropy_pool[1];
+
+ return true;
+}