blob: aba047fd50585b7aa282517a7009dca0bfb1ec77 [file] [log] [blame]
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2014-2016, STMicroelectronics International N.V.
*/
#include <io.h>
#include <kernel/panic.h>
#include <mm/core_mmu.h>
#include <mm/core_memprot.h>
#include <platform_config.h>
#include <trace.h>
#include "rng_support.h"
/* Address of the register to read in the RNG IP */
#define RNG_VAL_OFFSET 0x24
#define RNG_STATUS_OFFSET 0x20
#define RNG_STATUS_ERR0 BIT32(0)
#define RNG_STATUS_ERR1 BIT32(1)
#define RNG_STATUS_FULL BIT32(5)
static vaddr_t rng_base(void)
{
static void *va;
if (cpu_mmu_enabled()) {
if (!va)
va = phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC);
return (vaddr_t)va;
}
return RNG_BASE;
}
static inline int hwrng_waithost_fifo_full(void)
{
uint32_t status;
do {
status = io_read32(rng_base() + RNG_STATUS_OFFSET);
} while (!(status & RNG_STATUS_FULL));
if (status & (RNG_STATUS_ERR0 | RNG_STATUS_ERR1))
return 1;
return 0;
}
uint8_t hw_get_random_byte(void)
{
/*
* Only the HW RNG IP is used to generate the value through the
* HOST interface.
*
* @see the document rng_fspec_revG_120720.pdf for details
*
* - HOST FIFO size = 8x8b (64b)
* - LSB (16b) of the RNG_VAL register allows to read 16b
* - bit5 of the RNG_STATUS register allows to known if the HOST
* FIFO is full or not.
* - bit1,0 of the RNG_STATUS register allows to known if the
* data are valid.
*
* Main principle:
* For performance reason, a local SW fifo is used to store the
* content of the HOST FIFO (max size = 8bytes). When a random
* value is expected, this SW fifo is used to return a stored value.
* When the local SW fifo is empty, it is filled with the HOST FIFO
* according the following sequence:
*
* - wait HOST FIFO full
* o Indicates that max 8-bytes (64b) are available
* o This is mandatory to guarantee that a valid data is
* available. No STATUS bit to indicate that the HOST FIFO
* is empty is provided.
* - check STATUS bits
* - update the local SW fifo with the HOST FIFO
*
* This avoid to wait at each iteration that a valid random value is
* available. _LOCAL_FIFO_SIZE indicates the size of the local SW fifo.
*
*/
#define _LOCAL_FIFO_SIZE 8 /* min 2, 4, 6, max 8 */
static uint8_t lfifo[_LOCAL_FIFO_SIZE]; /* local fifo */
static int pos = -1;
static int nbcall; /* debug purpose - 0 is the initial value*/
volatile uint32_t tmpval[_LOCAL_FIFO_SIZE/2];
uint8_t value;
int i;
nbcall++;
/* Retrieve data from local fifo */
if (pos >= 0) {
pos++;
value = lfifo[pos];
if (pos == (_LOCAL_FIFO_SIZE - 1))
pos = -1;
return value;
}
if (hwrng_waithost_fifo_full())
return 0;
/* Read the FIFO according the number of expected element */
for (i = 0; i < _LOCAL_FIFO_SIZE / 2; i++)
tmpval[i] = io_read32(rng_base() + RNG_VAL_OFFSET) & 0xFFFF;
/* Update the local SW fifo for next request */
pos = 0;
for (i = 0; i < _LOCAL_FIFO_SIZE / 2; i++) {
lfifo[pos] = tmpval[i] & 0xFF;
pos++;
lfifo[pos] = (tmpval[i] >> 8) & 0xFF;
pos++;
};
pos = 0;
return lfifo[pos];
}