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