1 /* 2 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <arm_acle.h> 8 #include <assert.h> 9 #include <stdbool.h> 10 #include <stdint.h> 11 #include <string.h> 12 13 #include <lib/mmio.h> 14 #include <lib/utils_def.h> 15 #include <platform_def.h> 16 17 #include <lib/smccc.h> 18 #include <services/trng_svc.h> 19 #include <smccc_helpers.h> 20 21 #include <plat/common/platform.h> 22 23 #define NSAMPLE_CLOCKS 1 /* min 1 cycle, max 231 cycles */ 24 #define NRETRIES 5 25 26 /* initialised to false */ 27 static bool juno_trng_initialized; 28 29 static bool output_valid(void) 30 { 31 int i; 32 33 for (i = 0; i < NRETRIES; i++) { 34 uint32_t val; 35 36 val = mmio_read_32(TRNG_BASE + TRNG_STATUS); 37 if (val & 1U) 38 return true; 39 } 40 return false; /* No output data available. */ 41 } 42 43 DEFINE_SVC_UUID2(_plat_trng_uuid, 44 0x23523c58, 0x7448, 0x4083, 0x9d, 0x16, 45 0xe3, 0xfa, 0xb9, 0xf1, 0x73, 0xbc 46 ); 47 uuid_t plat_trng_uuid; 48 49 static uint32_t crc_value = ~0U; 50 51 /* 52 * Uses the Trusted Entropy Source peripheral on Juno to return 8 bytes of 53 * entropy. Returns 'true' when done successfully, 'false' otherwise. 54 */ 55 bool plat_get_entropy(uint64_t *out) 56 { 57 uint64_t ret; 58 59 assert(out); 60 assert(!check_uptr_overflow((uintptr_t)out, sizeof(*out))); 61 62 if (!juno_trng_initialized) { 63 /* Disable interrupt mode. */ 64 mmio_write_32(TRNG_BASE + TRNG_INTMASK, 0); 65 /* Program TRNG to sample for `NSAMPLE_CLOCKS`. */ 66 mmio_write_32(TRNG_BASE + TRNG_CONFIG, NSAMPLE_CLOCKS); 67 /* Abort any potentially pending sampling. */ 68 mmio_write_32(TRNG_BASE + TRNG_CONTROL, 2); 69 /* Reset TRNG outputs. */ 70 mmio_write_32(TRNG_BASE + TRNG_STATUS, 1); 71 72 juno_trng_initialized = true; 73 } 74 75 if (!output_valid()) { 76 /* Start TRNG. */ 77 mmio_write_32(TRNG_BASE + TRNG_CONTROL, 1); 78 79 if (!output_valid()) 80 return false; 81 } 82 83 /* CRC each two 32-bit registers together, combine the pairs */ 84 crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 0)); 85 crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 4)); 86 ret = (uint64_t)crc_value << 32; 87 88 crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 8)); 89 crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 12)); 90 *out = ret | crc_value; 91 92 /* Acknowledge current cycle, clear output registers. */ 93 mmio_write_32(TRNG_BASE + TRNG_STATUS, 1); 94 /* Trigger next TRNG cycle. */ 95 mmio_write_32(TRNG_BASE + TRNG_CONTROL, 1); 96 97 return true; 98 } 99 100 void plat_entropy_setup(void) 101 { 102 uint64_t dummy; 103 104 plat_trng_uuid = _plat_trng_uuid; 105 106 /* Initialise the entropy source and trigger RNG generation */ 107 plat_get_entropy(&dummy); 108 } 109