1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <string.h> 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <lib/mmio.h> 11*91f16700Schasinglulu 12*91f16700Schasinglulu #include <rpi_hw.h> 13*91f16700Schasinglulu 14*91f16700Schasinglulu /* Initial amount of values to discard */ 15*91f16700Schasinglulu #define RNG_WARMUP_COUNT U(0x40000) 16*91f16700Schasinglulu 17*91f16700Schasinglulu static void rpi3_rng_initialize(void) 18*91f16700Schasinglulu { 19*91f16700Schasinglulu uint32_t int_mask, ctrl; 20*91f16700Schasinglulu 21*91f16700Schasinglulu /* Return if it is already enabled */ 22*91f16700Schasinglulu ctrl = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET); 23*91f16700Schasinglulu if ((ctrl & RPI3_RNG_CTRL_ENABLE) != 0U) { 24*91f16700Schasinglulu return; 25*91f16700Schasinglulu } 26*91f16700Schasinglulu 27*91f16700Schasinglulu /* Mask interrupts */ 28*91f16700Schasinglulu int_mask = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET); 29*91f16700Schasinglulu int_mask |= RPI3_RNG_INT_MASK_DISABLE; 30*91f16700Schasinglulu mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET, int_mask); 31*91f16700Schasinglulu 32*91f16700Schasinglulu /* Discard several values when initializing to give it time to warmup */ 33*91f16700Schasinglulu mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET, RNG_WARMUP_COUNT); 34*91f16700Schasinglulu 35*91f16700Schasinglulu mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET, 36*91f16700Schasinglulu RPI3_RNG_CTRL_ENABLE); 37*91f16700Schasinglulu } 38*91f16700Schasinglulu 39*91f16700Schasinglulu static uint32_t rpi3_rng_get_word(void) 40*91f16700Schasinglulu { 41*91f16700Schasinglulu size_t nwords; 42*91f16700Schasinglulu 43*91f16700Schasinglulu do { 44*91f16700Schasinglulu /* Get number of available words to read */ 45*91f16700Schasinglulu nwords = (mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET) 46*91f16700Schasinglulu >> RPI3_RNG_STATUS_NUM_WORDS_SHIFT) 47*91f16700Schasinglulu & RPI3_RNG_STATUS_NUM_WORDS_MASK; 48*91f16700Schasinglulu } while (nwords == 0U); 49*91f16700Schasinglulu 50*91f16700Schasinglulu return mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_DATA_OFFSET); 51*91f16700Schasinglulu } 52*91f16700Schasinglulu 53*91f16700Schasinglulu void rpi3_rng_read(void *buf, size_t len) 54*91f16700Schasinglulu { 55*91f16700Schasinglulu uint32_t data; 56*91f16700Schasinglulu size_t left = len; 57*91f16700Schasinglulu uint32_t *dst = buf; 58*91f16700Schasinglulu 59*91f16700Schasinglulu assert(buf != NULL); 60*91f16700Schasinglulu assert(len != 0U); 61*91f16700Schasinglulu assert(check_uptr_overflow((uintptr_t) buf, (uintptr_t) len) == 0); 62*91f16700Schasinglulu 63*91f16700Schasinglulu rpi3_rng_initialize(); 64*91f16700Schasinglulu 65*91f16700Schasinglulu while (left >= sizeof(uint32_t)) { 66*91f16700Schasinglulu data = rpi3_rng_get_word(); 67*91f16700Schasinglulu *dst++ = data; 68*91f16700Schasinglulu left -= sizeof(uint32_t); 69*91f16700Schasinglulu } 70*91f16700Schasinglulu 71*91f16700Schasinglulu if (left > 0U) { 72*91f16700Schasinglulu data = rpi3_rng_get_word(); 73*91f16700Schasinglulu memcpy(dst, &data, left); 74*91f16700Schasinglulu } 75*91f16700Schasinglulu } 76