mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2026-07-08 13:21:01 +00:00
Armada-7K/8K and CN913x integrated the Rambus EIP-97 IP on CP11x die. It supports to generate up to 4 32-bit random number in one shot. This trivial driver provisions a simple API to read the random numbers from hardware. It allows the bootloader to get one 32-bit or 64-bit random number via SMC call to support KASLR. Change-Id: I1707a85512ca163b8c7ab1644ff0f7e2fcf57344 Signed-off-by: Wilson Ding <dingwei@marvell.com>
100 lines
2.6 KiB
C
100 lines
2.6 KiB
C
/*
|
|
* Copyright (c) 2025, Marvell Technology Group Ltd. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <common/debug.h>
|
|
#include <drivers/delay_timer.h>
|
|
#include <lib/mmio.h>
|
|
|
|
#include <mvebu_def.h>
|
|
|
|
/* Bind to first CP110's EIP-76 engine only */
|
|
#define CP110_TRNG_REGS_BASE (MVEBU_CP_REGS_BASE(0) + 0x760000U)
|
|
|
|
/* EIP-76 Register Definitions */
|
|
#define CP110_TRNG_OUTPUT_REG(n) (CP110_TRNG_REGS_BASE + ((n) * 0x4U))
|
|
#define CP110_TRNG_STAT_N_ACK_REG (CP110_TRNG_REGS_BASE + 0x10U)
|
|
#define CP110_TRNG_CONTROL_REG (CP110_TRNG_REGS_BASE + 0x14U)
|
|
#define CP110_TRNG_CONFIG_REG (CP110_TRNG_REGS_BASE + 0x18U)
|
|
#define CP110_TRNG_FRO_ENABLE_REG (CP110_TRNG_REGS_BASE + 0x20U)
|
|
#define CP110_TRNG_FRO_DETUNE_REG (CP110_TRNG_REGS_BASE + 0x24U)
|
|
|
|
/* CP110_TRNG_STAT_N_ACK_REG */
|
|
#define CP110_TRNG_READY BIT(0)
|
|
|
|
/* CP110_TRNG_CONTROL_REG */
|
|
#define CP110_TRNG_EN BIT(10)
|
|
|
|
/* CP110_TRNG_CONFIG_REG */
|
|
#define CP110_TRNG_NOISE_BLOCKS_SHIFT 0U
|
|
#define CP110_TRNG_NOISE_BLOCKS_MASK (0xFFU << CP110_TRNG_NOISE_BLOCKS_SHIFT)
|
|
#define CP110_TRNG_SAMPLE_CYCLES_SHIFT 16U
|
|
#define CP110_TRNG_SAMPLE_CYCLES_MASK (0xFFU << CP110_TRNG_SAMPLE_CYCLES_SHIFT)
|
|
|
|
/* CP110_TRNG_FRO_ENABLE_REG */
|
|
#define CP110_TRNG_FRO_EN_SHIFT 0U
|
|
#define CP110_TRNG_FRO_EN_MASK (0xFFFFFFU << CP110_TRNG_FRO_EN_SHIFT)
|
|
|
|
#define CP110_TRNG_MAX_OUTPUTS 4U
|
|
|
|
/* maximum busy wait */
|
|
#define CP110_TRNG_MAX_RETRIES 3U
|
|
|
|
static void mv_trng_init(void)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = (0x5U << CP110_TRNG_NOISE_BLOCKS_SHIFT) & CP110_TRNG_NOISE_BLOCKS_MASK;
|
|
val |= (0x22U << CP110_TRNG_SAMPLE_CYCLES_SHIFT) & CP110_TRNG_SAMPLE_CYCLES_MASK;
|
|
mmio_write_32(CP110_TRNG_CONFIG_REG, val);
|
|
|
|
mmio_write_32(CP110_TRNG_FRO_DETUNE_REG, 0U);
|
|
mmio_write_32(CP110_TRNG_FRO_ENABLE_REG, CP110_TRNG_FRO_EN_MASK);
|
|
|
|
mmio_write_32(CP110_TRNG_CONTROL_REG, CP110_TRNG_EN);
|
|
}
|
|
|
|
int mv_trng_get_random32(uint32_t *rand, uint8_t num)
|
|
{
|
|
uint32_t val;
|
|
uint8_t i;
|
|
|
|
if (num > CP110_TRNG_MAX_OUTPUTS) {
|
|
return -1;
|
|
}
|
|
|
|
val = mmio_read_32(CP110_TRNG_CONTROL_REG);
|
|
if ((val & CP110_TRNG_EN) != 0U) {
|
|
/* Flush the staled output data */
|
|
val = mmio_read_32(CP110_TRNG_STAT_N_ACK_REG);
|
|
if ((val & CP110_TRNG_READY) != 0U) {
|
|
mmio_write_32(CP110_TRNG_STAT_N_ACK_REG, CP110_TRNG_READY);
|
|
}
|
|
} else {
|
|
mv_trng_init();
|
|
/* Necessary delay for the warm-up */
|
|
udelay(200U);
|
|
}
|
|
|
|
|
|
for (i = 0U; i < CP110_TRNG_MAX_RETRIES; i++) {
|
|
val = mmio_read_32(CP110_TRNG_STAT_N_ACK_REG);
|
|
if ((val & CP110_TRNG_READY) != 0U) {
|
|
break;
|
|
}
|
|
udelay(1U);
|
|
}
|
|
|
|
if (i == CP110_TRNG_MAX_RETRIES) {
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0U; i < num; i++) {
|
|
rand[i] = mmio_read_32(CP110_TRNG_OUTPUT_REG(i));
|
|
}
|
|
|
|
return 0;
|
|
}
|