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