/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "rpi3_hw.h" /* Initial amount of values to discard */ #define RNG_WARMUP_COUNT U(0x40000) static void rpi3_rng_initialize(void) { uint32_t int_mask, ctrl; /* Return if it is already enabled */ ctrl = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET); if ((ctrl & RPI3_RNG_CTRL_ENABLE) != 0U) { return; } /* Mask interrupts */ int_mask = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET); int_mask |= RPI3_RNG_INT_MASK_DISABLE; mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET, int_mask); /* Discard several values when initializing to give it time to warmup */ mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET, RNG_WARMUP_COUNT); mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET, RPI3_RNG_CTRL_ENABLE); } static uint32_t rpi3_rng_get_word(void) { size_t nwords; do { /* Get number of available words to read */ nwords = (mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET) >> RPI3_RNG_STATUS_NUM_WORDS_SHIFT) & RPI3_RNG_STATUS_NUM_WORDS_MASK; } while (nwords == 0U); return mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_DATA_OFFSET); } void rpi3_rng_read(void *buf, size_t len) { uint32_t data; size_t left = len; uint32_t *dst = buf; assert(buf != NULL); assert(len != 0U); assert(check_uptr_overflow((uintptr_t) buf, (uintptr_t) len) == 0); rpi3_rng_initialize(); while (left >= sizeof(uint32_t)) { data = rpi3_rng_get_word(); *dst++ = data; left -= sizeof(uint32_t); } if (left > 0U) { data = rpi3_rng_get_word(); memcpy(dst, &data, left); } }