xref: /rk3399_ARM-atf/plat/arm/board/juno/juno_trng.c (revision 543f0d8b0864b232f014a0fb9d98e46ed52d4442)
1df9a39eaSdp-arm /*
2fd116b9fSRoberto Vargas  * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3df9a39eaSdp-arm  *
482cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
5df9a39eaSdp-arm  */
6df9a39eaSdp-arm 
7df9a39eaSdp-arm #include <assert.h>
8*543f0d8bSAndre Przywara #include <stdbool.h>
9*543f0d8bSAndre Przywara #include <stdint.h>
10df9a39eaSdp-arm #include <string.h>
1109d40e0eSAntonio Nino Diaz 
1209d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
1309d40e0eSAntonio Nino Diaz #include <lib/utils_def.h>
14234bc7f8SAntonio Nino Diaz #include <platform_def.h>
1509d40e0eSAntonio Nino Diaz 
16fd116b9fSRoberto Vargas #include "juno_decl.h"
17df9a39eaSdp-arm 
18df9a39eaSdp-arm #define NSAMPLE_CLOCKS	1 /* min 1 cycle, max 231 cycles */
19df9a39eaSdp-arm #define NRETRIES	5
20df9a39eaSdp-arm 
21*543f0d8bSAndre Przywara /* initialised to false */
22*543f0d8bSAndre Przywara static bool juno_trng_initialized;
23*543f0d8bSAndre Przywara 
24*543f0d8bSAndre Przywara static bool output_valid(void)
25df9a39eaSdp-arm {
26df9a39eaSdp-arm 	int i;
27df9a39eaSdp-arm 
28df9a39eaSdp-arm 	for (i = 0; i < NRETRIES; i++) {
29df9a39eaSdp-arm 		uint32_t val;
30df9a39eaSdp-arm 
31df9a39eaSdp-arm 		val = mmio_read_32(TRNG_BASE + TRNG_STATUS);
32df9a39eaSdp-arm 		if (val & 1U)
33*543f0d8bSAndre Przywara 			return true;
34df9a39eaSdp-arm 	}
35*543f0d8bSAndre Przywara 	return false; /* No output data available. */
36df9a39eaSdp-arm }
37df9a39eaSdp-arm 
38df9a39eaSdp-arm /*
39*543f0d8bSAndre Przywara  * This function fills `buf` with 8 bytes of entropy.
40df9a39eaSdp-arm  * It uses the Trusted Entropy Source peripheral on Juno.
41*543f0d8bSAndre Przywara  * Returns 'true' when the buffer has been filled with entropy
42*543f0d8bSAndre Przywara  * successfully, or 'false' otherwise.
43df9a39eaSdp-arm  */
44*543f0d8bSAndre Przywara bool juno_getentropy(uint64_t *buf)
45df9a39eaSdp-arm {
46*543f0d8bSAndre Przywara 	uint64_t ret;
47df9a39eaSdp-arm 
48df9a39eaSdp-arm 	assert(buf);
49*543f0d8bSAndre Przywara 	assert(!check_uptr_overflow((uintptr_t)buf, sizeof(*buf)));
50df9a39eaSdp-arm 
51*543f0d8bSAndre Przywara 	if (!juno_trng_initialized) {
52df9a39eaSdp-arm 		/* Disable interrupt mode. */
53df9a39eaSdp-arm 		mmio_write_32(TRNG_BASE + TRNG_INTMASK, 0);
54df9a39eaSdp-arm 		/* Program TRNG to sample for `NSAMPLE_CLOCKS`. */
55df9a39eaSdp-arm 		mmio_write_32(TRNG_BASE + TRNG_CONFIG, NSAMPLE_CLOCKS);
56*543f0d8bSAndre Przywara 		/* Abort any potentially pending sampling. */
57*543f0d8bSAndre Przywara 		mmio_write_32(TRNG_BASE + TRNG_CONTROL, 2);
58*543f0d8bSAndre Przywara 		/* Reset TRNG outputs. */
59*543f0d8bSAndre Przywara 		mmio_write_32(TRNG_BASE + TRNG_STATUS, 1);
60df9a39eaSdp-arm 
61*543f0d8bSAndre Przywara 		juno_trng_initialized = true;
62*543f0d8bSAndre Przywara 	}
63df9a39eaSdp-arm 
64*543f0d8bSAndre Przywara 	if (!output_valid()) {
65df9a39eaSdp-arm 		/* Start TRNG. */
66df9a39eaSdp-arm 		mmio_write_32(TRNG_BASE + TRNG_CONTROL, 1);
67df9a39eaSdp-arm 
68df9a39eaSdp-arm 		if (!output_valid())
69*543f0d8bSAndre Przywara 			return false;
70df9a39eaSdp-arm 	}
71df9a39eaSdp-arm 
72*543f0d8bSAndre Przywara 	/* XOR each two 32-bit registers together, combine the pairs */
73*543f0d8bSAndre Przywara 	ret = mmio_read_32(TRNG_BASE + 0);
74*543f0d8bSAndre Przywara 	ret ^= mmio_read_32(TRNG_BASE + 4);
75*543f0d8bSAndre Przywara 	ret <<= 32;
76*543f0d8bSAndre Przywara 
77*543f0d8bSAndre Przywara 	ret |= mmio_read_32(TRNG_BASE + 8);
78*543f0d8bSAndre Przywara 	ret ^= mmio_read_32(TRNG_BASE + 12);
79*543f0d8bSAndre Przywara 	*buf = ret;
80*543f0d8bSAndre Przywara 
81*543f0d8bSAndre Przywara 	/* Acknowledge current cycle, clear output registers. */
82df9a39eaSdp-arm 	mmio_write_32(TRNG_BASE + TRNG_STATUS, 1);
83*543f0d8bSAndre Przywara 	/* Trigger next TRNG cycle. */
84*543f0d8bSAndre Przywara 	mmio_write_32(TRNG_BASE + TRNG_CONTROL, 1);
85df9a39eaSdp-arm 
86*543f0d8bSAndre Przywara 	return true;
87df9a39eaSdp-arm }
88