xref: /rk3399_ARM-atf/plat/arm/board/juno/juno_trng.c (revision cb5f0faa71693c268ce1f0f48633bf7de2abb442)
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 
7eb18ce32SAndre Przywara #include <arm_acle.h>
8df9a39eaSdp-arm #include <assert.h>
9543f0d8bSAndre Przywara #include <stdbool.h>
10543f0d8bSAndre Przywara #include <stdint.h>
11df9a39eaSdp-arm #include <string.h>
1209d40e0eSAntonio Nino Diaz 
1309d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
1409d40e0eSAntonio Nino Diaz #include <lib/utils_def.h>
15234bc7f8SAntonio Nino Diaz #include <platform_def.h>
1609d40e0eSAntonio Nino Diaz 
17*cb5f0faaSAndre Przywara #include <lib/smccc.h>
18*cb5f0faaSAndre Przywara #include <services/trng_svc.h>
19*cb5f0faaSAndre Przywara #include <smccc_helpers.h>
20*cb5f0faaSAndre Przywara 
21*cb5f0faaSAndre Przywara #include <plat/common/platform.h>
22df9a39eaSdp-arm 
23df9a39eaSdp-arm #define NSAMPLE_CLOCKS	1 /* min 1 cycle, max 231 cycles */
24df9a39eaSdp-arm #define NRETRIES	5
25df9a39eaSdp-arm 
26543f0d8bSAndre Przywara /* initialised to false */
27543f0d8bSAndre Przywara static bool juno_trng_initialized;
28543f0d8bSAndre Przywara 
29543f0d8bSAndre Przywara static bool output_valid(void)
30df9a39eaSdp-arm {
31df9a39eaSdp-arm 	int i;
32df9a39eaSdp-arm 
33df9a39eaSdp-arm 	for (i = 0; i < NRETRIES; i++) {
34df9a39eaSdp-arm 		uint32_t val;
35df9a39eaSdp-arm 
36df9a39eaSdp-arm 		val = mmio_read_32(TRNG_BASE + TRNG_STATUS);
37df9a39eaSdp-arm 		if (val & 1U)
38543f0d8bSAndre Przywara 			return true;
39df9a39eaSdp-arm 	}
40543f0d8bSAndre Przywara 	return false; /* No output data available. */
41df9a39eaSdp-arm }
42df9a39eaSdp-arm 
43*cb5f0faaSAndre Przywara DEFINE_SVC_UUID2(_plat_trng_uuid,
44*cb5f0faaSAndre Przywara 	0x23523c58, 0x7448, 0x4083, 0x9d, 0x16,
45*cb5f0faaSAndre Przywara 	0xe3, 0xfa, 0xb9, 0xf1, 0x73, 0xbc
46*cb5f0faaSAndre Przywara );
47*cb5f0faaSAndre Przywara uuid_t plat_trng_uuid;
48*cb5f0faaSAndre Przywara 
49eb18ce32SAndre Przywara static uint32_t crc_value = ~0U;
50eb18ce32SAndre Przywara 
51df9a39eaSdp-arm /*
52*cb5f0faaSAndre Przywara  * Uses the Trusted Entropy Source peripheral on Juno to return 8 bytes of
53*cb5f0faaSAndre Przywara  * entropy. Returns 'true' when done successfully, 'false' otherwise.
54df9a39eaSdp-arm  */
55*cb5f0faaSAndre Przywara bool plat_get_entropy(uint64_t *out)
56df9a39eaSdp-arm {
57543f0d8bSAndre Przywara 	uint64_t ret;
58df9a39eaSdp-arm 
59*cb5f0faaSAndre Przywara 	assert(out);
60*cb5f0faaSAndre Przywara 	assert(!check_uptr_overflow((uintptr_t)out, sizeof(*out)));
61df9a39eaSdp-arm 
62543f0d8bSAndre Przywara 	if (!juno_trng_initialized) {
63df9a39eaSdp-arm 		/* Disable interrupt mode. */
64df9a39eaSdp-arm 		mmio_write_32(TRNG_BASE + TRNG_INTMASK, 0);
65df9a39eaSdp-arm 		/* Program TRNG to sample for `NSAMPLE_CLOCKS`. */
66df9a39eaSdp-arm 		mmio_write_32(TRNG_BASE + TRNG_CONFIG, NSAMPLE_CLOCKS);
67543f0d8bSAndre Przywara 		/* Abort any potentially pending sampling. */
68543f0d8bSAndre Przywara 		mmio_write_32(TRNG_BASE + TRNG_CONTROL, 2);
69543f0d8bSAndre Przywara 		/* Reset TRNG outputs. */
70543f0d8bSAndre Przywara 		mmio_write_32(TRNG_BASE + TRNG_STATUS, 1);
71df9a39eaSdp-arm 
72543f0d8bSAndre Przywara 		juno_trng_initialized = true;
73543f0d8bSAndre Przywara 	}
74df9a39eaSdp-arm 
75543f0d8bSAndre Przywara 	if (!output_valid()) {
76df9a39eaSdp-arm 		/* Start TRNG. */
77df9a39eaSdp-arm 		mmio_write_32(TRNG_BASE + TRNG_CONTROL, 1);
78df9a39eaSdp-arm 
79df9a39eaSdp-arm 		if (!output_valid())
80543f0d8bSAndre Przywara 			return false;
81df9a39eaSdp-arm 	}
82df9a39eaSdp-arm 
83eb18ce32SAndre Przywara 	/* CRC each two 32-bit registers together, combine the pairs */
84eb18ce32SAndre Przywara 	crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 0));
85eb18ce32SAndre Przywara 	crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 4));
86eb18ce32SAndre Przywara 	ret = (uint64_t)crc_value << 32;
87543f0d8bSAndre Przywara 
88eb18ce32SAndre Przywara 	crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 8));
89eb18ce32SAndre Przywara 	crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 12));
90*cb5f0faaSAndre Przywara 	*out = ret | crc_value;
91543f0d8bSAndre Przywara 
92543f0d8bSAndre Przywara 	/* Acknowledge current cycle, clear output registers. */
93df9a39eaSdp-arm 	mmio_write_32(TRNG_BASE + TRNG_STATUS, 1);
94543f0d8bSAndre Przywara 	/* Trigger next TRNG cycle. */
95543f0d8bSAndre Przywara 	mmio_write_32(TRNG_BASE + TRNG_CONTROL, 1);
96df9a39eaSdp-arm 
97543f0d8bSAndre Przywara 	return true;
98df9a39eaSdp-arm }
99*cb5f0faaSAndre Przywara 
100*cb5f0faaSAndre Przywara void plat_entropy_setup(void)
101*cb5f0faaSAndre Przywara {
102*cb5f0faaSAndre Przywara 	uint64_t dummy;
103*cb5f0faaSAndre Przywara 
104*cb5f0faaSAndre Przywara 	plat_trng_uuid = _plat_trng_uuid;
105*cb5f0faaSAndre Przywara 
106*cb5f0faaSAndre Przywara 	/* Initialise the entropy source and trigger RNG generation */
107*cb5f0faaSAndre Przywara 	plat_get_entropy(&dummy);
108*cb5f0faaSAndre Przywara }
109