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
output_valid(void)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 */
plat_get_entropy(uint64_t * out)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
plat_entropy_setup(void)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