1 /* 2 * Copyright (c) 2018-2024, 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 #define RPI3_RNG_CTRL_OFFSET ULL(0x00000000) 15 #define RPI3_RNG_STATUS_OFFSET ULL(0x00000004) 16 #define RPI3_RNG_DATA_OFFSET ULL(0x00000008) 17 #define RPI3_RNG_INT_MASK_OFFSET ULL(0x00000010) 18 /* Enable/disable RNG */ 19 #define RPI3_RNG_CTRL_ENABLE U(0x1) 20 #define RPI3_RNG_CTRL_DISABLE U(0x0) 21 /* Number of currently available words */ 22 #define RPI3_RNG_STATUS_NUM_WORDS_SHIFT U(24) 23 #define RPI3_RNG_STATUS_NUM_WORDS_MASK U(0xFF) 24 /* Value to mask interrupts caused by the RNG */ 25 #define RPI3_RNG_INT_MASK_DISABLE U(0x1) 26 27 /* Initial amount of values to discard */ 28 #define RNG_WARMUP_COUNT U(0x40000) 29 30 static void rpi3_rng_initialize(void) 31 { 32 uint32_t int_mask, ctrl; 33 34 /* Return if it is already enabled */ 35 ctrl = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET); 36 if ((ctrl & RPI3_RNG_CTRL_ENABLE) != 0U) { 37 return; 38 } 39 40 /* Mask interrupts */ 41 int_mask = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET); 42 int_mask |= RPI3_RNG_INT_MASK_DISABLE; 43 mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET, int_mask); 44 45 /* Discard several values when initializing to give it time to warmup */ 46 mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET, RNG_WARMUP_COUNT); 47 48 mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET, 49 RPI3_RNG_CTRL_ENABLE); 50 } 51 52 static uint32_t rpi3_rng_get_word(void) 53 { 54 size_t nwords; 55 56 do { 57 /* Get number of available words to read */ 58 nwords = (mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET) 59 >> RPI3_RNG_STATUS_NUM_WORDS_SHIFT) 60 & RPI3_RNG_STATUS_NUM_WORDS_MASK; 61 } while (nwords == 0U); 62 63 return mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_DATA_OFFSET); 64 } 65 66 void rpi3_rng_read(void *buf, size_t len) 67 { 68 uint32_t data; 69 size_t left = len; 70 uint32_t *dst = buf; 71 72 assert(buf != NULL); 73 assert(len != 0U); 74 assert(check_uptr_overflow((uintptr_t) buf, (uintptr_t) len) == 0); 75 76 rpi3_rng_initialize(); 77 78 while (left >= sizeof(uint32_t)) { 79 data = rpi3_rng_get_word(); 80 *dst++ = data; 81 left -= sizeof(uint32_t); 82 } 83 84 if (left > 0U) { 85 data = rpi3_rng_get_word(); 86 memcpy(dst, &data, left); 87 } 88 } 89