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