1990ab78eSAndre Przywara /* 2*7a9cdf58SMario Bălănică * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved. 3990ab78eSAndre Przywara * 4990ab78eSAndre Przywara * SPDX-License-Identifier: BSD-3-Clause 5990ab78eSAndre Przywara */ 6990ab78eSAndre Przywara 7990ab78eSAndre Przywara #include <assert.h> 8990ab78eSAndre Przywara #include <string.h> 9990ab78eSAndre Przywara 10990ab78eSAndre Przywara #include <lib/mmio.h> 11990ab78eSAndre Przywara 12990ab78eSAndre Przywara #include <rpi_hw.h> 13990ab78eSAndre Przywara 14*7a9cdf58SMario Bălănică #define RPI3_RNG_CTRL_OFFSET ULL(0x00000000) 15*7a9cdf58SMario Bălănică #define RPI3_RNG_STATUS_OFFSET ULL(0x00000004) 16*7a9cdf58SMario Bălănică #define RPI3_RNG_DATA_OFFSET ULL(0x00000008) 17*7a9cdf58SMario Bălănică #define RPI3_RNG_INT_MASK_OFFSET ULL(0x00000010) 18*7a9cdf58SMario Bălănică /* Enable/disable RNG */ 19*7a9cdf58SMario Bălănică #define RPI3_RNG_CTRL_ENABLE U(0x1) 20*7a9cdf58SMario Bălănică #define RPI3_RNG_CTRL_DISABLE U(0x0) 21*7a9cdf58SMario Bălănică /* Number of currently available words */ 22*7a9cdf58SMario Bălănică #define RPI3_RNG_STATUS_NUM_WORDS_SHIFT U(24) 23*7a9cdf58SMario Bălănică #define RPI3_RNG_STATUS_NUM_WORDS_MASK U(0xFF) 24*7a9cdf58SMario Bălănică /* Value to mask interrupts caused by the RNG */ 25*7a9cdf58SMario Bălănică #define RPI3_RNG_INT_MASK_DISABLE U(0x1) 26*7a9cdf58SMario Bălănică 27990ab78eSAndre Przywara /* Initial amount of values to discard */ 28990ab78eSAndre Przywara #define RNG_WARMUP_COUNT U(0x40000) 29990ab78eSAndre Przywara 30990ab78eSAndre Przywara static void rpi3_rng_initialize(void) 31990ab78eSAndre Przywara { 32990ab78eSAndre Przywara uint32_t int_mask, ctrl; 33990ab78eSAndre Przywara 34990ab78eSAndre Przywara /* Return if it is already enabled */ 35990ab78eSAndre Przywara ctrl = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET); 36990ab78eSAndre Przywara if ((ctrl & RPI3_RNG_CTRL_ENABLE) != 0U) { 37990ab78eSAndre Przywara return; 38990ab78eSAndre Przywara } 39990ab78eSAndre Przywara 40990ab78eSAndre Przywara /* Mask interrupts */ 41990ab78eSAndre Przywara int_mask = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET); 42990ab78eSAndre Przywara int_mask |= RPI3_RNG_INT_MASK_DISABLE; 43990ab78eSAndre Przywara mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET, int_mask); 44990ab78eSAndre Przywara 45990ab78eSAndre Przywara /* Discard several values when initializing to give it time to warmup */ 46990ab78eSAndre Przywara mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET, RNG_WARMUP_COUNT); 47990ab78eSAndre Przywara 48990ab78eSAndre Przywara mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET, 49990ab78eSAndre Przywara RPI3_RNG_CTRL_ENABLE); 50990ab78eSAndre Przywara } 51990ab78eSAndre Przywara 52990ab78eSAndre Przywara static uint32_t rpi3_rng_get_word(void) 53990ab78eSAndre Przywara { 54990ab78eSAndre Przywara size_t nwords; 55990ab78eSAndre Przywara 56990ab78eSAndre Przywara do { 57990ab78eSAndre Przywara /* Get number of available words to read */ 58990ab78eSAndre Przywara nwords = (mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET) 59990ab78eSAndre Przywara >> RPI3_RNG_STATUS_NUM_WORDS_SHIFT) 60990ab78eSAndre Przywara & RPI3_RNG_STATUS_NUM_WORDS_MASK; 61990ab78eSAndre Przywara } while (nwords == 0U); 62990ab78eSAndre Przywara 63990ab78eSAndre Przywara return mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_DATA_OFFSET); 64990ab78eSAndre Przywara } 65990ab78eSAndre Przywara 66990ab78eSAndre Przywara void rpi3_rng_read(void *buf, size_t len) 67990ab78eSAndre Przywara { 68990ab78eSAndre Przywara uint32_t data; 69990ab78eSAndre Przywara size_t left = len; 70990ab78eSAndre Przywara uint32_t *dst = buf; 71990ab78eSAndre Przywara 72990ab78eSAndre Przywara assert(buf != NULL); 73990ab78eSAndre Przywara assert(len != 0U); 74990ab78eSAndre Przywara assert(check_uptr_overflow((uintptr_t) buf, (uintptr_t) len) == 0); 75990ab78eSAndre Przywara 76990ab78eSAndre Przywara rpi3_rng_initialize(); 77990ab78eSAndre Przywara 78990ab78eSAndre Przywara while (left >= sizeof(uint32_t)) { 79990ab78eSAndre Przywara data = rpi3_rng_get_word(); 80990ab78eSAndre Przywara *dst++ = data; 81990ab78eSAndre Przywara left -= sizeof(uint32_t); 82990ab78eSAndre Przywara } 83990ab78eSAndre Przywara 84990ab78eSAndre Przywara if (left > 0U) { 85990ab78eSAndre Przywara data = rpi3_rng_get_word(); 86990ab78eSAndre Przywara memcpy(dst, &data, left); 87990ab78eSAndre Przywara } 88990ab78eSAndre Przywara } 89