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