blob: 691b9233d6ced2ec298edfbcf7a5ab7484b41600 [file] [log] [blame]
/*
* 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;
}