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