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;
+}
diff --git a/plat/mediatek/drivers/rng/mt8186/rng_plat.h b/plat/mediatek/drivers/rng/mt8186/rng_plat.h
new file mode 100644
index 0000000..ab22c45
--- /dev/null
+++ b/plat/mediatek/drivers/rng/mt8186/rng_plat.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RNG_PLAT_H
+#define RNG_PLAT_H
+
+#define TRNG_TIME_OUT		1000
+#define MTK_TRNG_MAX_ROUND	4
+
+/*******************************************************************************
+ * TRNG related constants
+ ******************************************************************************/
+#define TRNG_BASE_SIZE		0x1000
+#define TRNG_CTRL		(TRNG_BASE + 0x0000)
+#define TRNG_TIME		(TRNG_BASE + 0x0004)
+#define TRNG_DATA		(TRNG_BASE + 0x0008)
+#define TRNG_CONF		(TRNG_BASE + 0x000C)
+#define TRNG_CTRL_RDY		0x80000000
+#define TRNG_CTRL_START		0x00000001
+#define TRNG_CONF_VON_EN	0x00000020
+#define TRNG_PDN_BASE_SIZE	0x1000
+#define TRNG_PDN_SET		(INFRACFG_AO_BASE + 0x0088)
+#define TRNG_PDN_CLR		(INFRACFG_AO_BASE + 0x008C)
+#define TRNG_PDN_STATUS		(INFRACFG_AO_BASE + 0x0094)
+#define TRNG_PDN_VALUE		0x200
+
+#endif /* RNG_PLAT_H */
diff --git a/plat/mediatek/drivers/rng/rng.c b/plat/mediatek/drivers/rng/rng.c
new file mode 100644
index 0000000..d611168
--- /dev/null
+++ b/plat/mediatek/drivers/rng/rng.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <lib/smccc.h>
+#include <plat/common/plat_trng.h>
+
+#include <mtk_sip_svc.h>
+
+DEFINE_SVC_UUID2(_plat_trng_uuid,
+	0xf6b2c8d9, 0x1abb, 0x4d83, 0xb2, 0x3f,
+	0x5c, 0x51, 0xb6, 0xef, 0xfc, 0xaf
+);
+uuid_t plat_trng_uuid;
+
+void plat_entropy_setup(void)
+{
+	uint64_t placeholder;
+
+	plat_trng_uuid = _plat_trng_uuid;
+
+	/* Initialise the entropy source and trigger RNG generation */
+	plat_get_entropy(&placeholder);
+}
diff --git a/plat/mediatek/drivers/rng/rules.mk b/plat/mediatek/drivers/rng/rules.mk
new file mode 100644
index 0000000..5bcd2cd
--- /dev/null
+++ b/plat/mediatek/drivers/rng/rules.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2024, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := rng
+
+PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
+PLAT_INCLUDES += -I${LOCAL_DIR}
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/rng.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/${MTK_SOC}/rng_plat.c
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/mt8186/include/platform_def.h b/plat/mediatek/mt8186/include/platform_def.h
index 98b88bd..707f4a5 100644
--- a/plat/mediatek/mt8186/include/platform_def.h
+++ b/plat/mediatek/mt8186/include/platform_def.h
@@ -77,6 +77,11 @@
 #define MSDC0_BASE		(IO_PHYS + 0x01230000)
 
 /*******************************************************************************
+ * TRNG related constants
+ ******************************************************************************/
+#define TRNG_BASE		(IO_PHYS + 0x0020F000)
+
+/*******************************************************************************
  * GIC-600 & interrupt handling related constants
  ******************************************************************************/
 /* Base MTK_platform compatible GIC memory map */
diff --git a/plat/mediatek/mt8186/platform.mk b/plat/mediatek/mt8186/platform.mk
index 2bd2fb4..9c03340 100644
--- a/plat/mediatek/mt8186/platform.mk
+++ b/plat/mediatek/mt8186/platform.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2021-2023, MediaTek Inc. All rights reserved.
+# Copyright (c) 2021-2024, MediaTek Inc. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -7,6 +7,9 @@
 MTK_PLAT     := plat/mediatek
 MTK_PLAT_SOC := ${MTK_PLAT}/${PLAT}
 
+# True Random Number Generator firmware Interface
+TRNG_SUPPORT := 1
+
 PLAT_INCLUDES := -I${MTK_PLAT}/common/                            \
                  -I${MTK_PLAT}/drivers/cirq/                      \
                  -I${MTK_PLAT}/drivers/gic600/                    \
@@ -79,6 +82,11 @@
                 ${MTK_PLAT_SOC}/plat_sip_calls.c                      \
                 ${MTK_PLAT_SOC}/plat_topology.c
 
+ifeq (${TRNG_SUPPORT},1)
+BL31_SOURCES += ${MTK_PLAT}/drivers/rng/rng.c                         \
+                ${MTK_PLAT}/drivers/rng/${PLAT}/rng_plat.c
+endif
+
 # Build SPM drivers
 include ${MTK_PLAT_SOC}/drivers/spm/build.mk