xref: /aosp_15_r20/external/arm-trusted-firmware/drivers/rpi3/rng/rpi3_rng.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
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