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