123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- /*
- * 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;
- }
|