/* * Copyright (c) 2024, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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; }