| // 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]; |
| } |