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 
rpi3_rng_initialize(void)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 
rpi3_rng_get_word(void)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 
rpi3_rng_read(void * buf,size_t len)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