Add hw TRNG from SEL0 SP

Intgrates the FVP TRNG into the crypto sp to provide a hw
entropy source.  Includes tests that check SP device
region configuration loading and MMIO access within the
region.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: Ia9af8b044596e1c7d194f039fdf64c2468bb3221
diff --git a/platform/drivers/arm/juno_trng/driver.cmake b/platform/drivers/arm/juno_trng/driver.cmake
new file mode 100644
index 0000000..6d51009
--- /dev/null
+++ b/platform/drivers/arm/juno_trng/driver.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+# Add source files for using juno_trng and adapting it to the platform
+# trng interface.
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/juno_trng.c"
+	"${CMAKE_CURRENT_LIST_DIR}/juno_trng_adapter.c"
+)
diff --git a/platform/drivers/arm/juno_trng/juno_decl.h b/platform/drivers/arm/juno_trng/juno_decl.h
new file mode 100644
index 0000000..07f2e19
--- /dev/null
+++ b/platform/drivers/arm/juno_trng/juno_decl.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This is a modified version of the juno trng platform driver from trusted-firmware-a.
+ * The code has been modified to allow the peripheral to be accessed by S-EL0 at
+ * an arbitrary virtual address.
+ */
+
+#ifndef JUNO_DECL_H
+#define JUNO_DECL_H
+
+#include <stdint.h>
+
+void juno_trng_set_base_addr(uintptr_t addr);
+int juno_getentropy(void *buf, size_t len);
+
+#endif /* JUNO_DECL_H */
diff --git a/platform/drivers/arm/juno_trng/juno_def.h b/platform/drivers/arm/juno_trng/juno_def.h
new file mode 100644
index 0000000..97d1e3c
--- /dev/null
+++ b/platform/drivers/arm/juno_trng/juno_def.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ *
+ * Based on the the trustedfirmware-a file with the same name.  All but the
+ * TRNG defines are stripped out.
+ */
+
+#ifndef JUNO_DEF_H
+#define JUNO_DEF_H
+
+/*******************************************************************************
+ * TRNG related constants
+ ******************************************************************************/
+#define TRNG_NOUTPUTS	4
+#define TRNG_STATUS	UL(0x10)
+#define TRNG_INTMASK	UL(0x14)
+#define TRNG_CONFIG	UL(0x18)
+#define TRNG_CONTROL	UL(0x1C)
+#define TRNG_NBYTES	16	/* Number of bytes generated per round. */
+
+
+
+#endif /* JUNO_DEF_H */
diff --git a/platform/drivers/arm/juno_trng/juno_trng.c b/platform/drivers/arm/juno_trng/juno_trng.c
new file mode 100644
index 0000000..b520dba
--- /dev/null
+++ b/platform/drivers/arm/juno_trng/juno_trng.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This is a modified version of the juno trng platform driver from trusted-firmware-a.
+ * The code has been modified to allow the peripheral to be accessed by S-EL0 at
+ * an arbitrary virtual address.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <util.h>
+#include "mmio.h"
+#include "juno_def.h"
+#include "juno_decl.h"
+
+/* The TRNG base address */
+static uintptr_t trng_base = 0;
+
+#define TRNG_BASE	trng_base
+#define NSAMPLE_CLOCKS	1 /* min 1 cycle, max 231 cycles */
+#define NRETRIES	5
+
+/*
+ * Sets the base address used to access the peripheral.  For
+ * S-EL0 operation, this will be a virtual address.
+ */
+void juno_trng_set_base_addr(uintptr_t addr)
+{
+	trng_base = addr;
+}
+
+static inline int output_valid(void)
+{
+	int i;
+
+	for (i = 0; i < NRETRIES; i++) {
+		uint32_t val;
+
+		val = mmio_read_32(TRNG_BASE + TRNG_STATUS);
+		if (val & 1U)
+			break;
+	}
+	if (i >= NRETRIES)
+		return 0; /* No output data available. */
+	return 1;
+}
+
+/*
+ * This function fills `buf` with `len` bytes of entropy.
+ * It uses the Trusted Entropy Source peripheral on Juno.
+ * Returns 0 when the buffer has been filled with entropy
+ * successfully and -1 otherwise.
+ */
+int juno_getentropy(void *buf, size_t len)
+{
+	uint8_t *bp = buf;
+
+	assert(buf);
+	assert(len);
+
+	/* Check for a valid base address */
+	if (!TRNG_BASE) return -1;
+
+	/* Disable interrupt mode. */
+	mmio_write_32(TRNG_BASE + TRNG_INTMASK, 0);
+	/* Program TRNG to sample for `NSAMPLE_CLOCKS`. */
+	mmio_write_32(TRNG_BASE + TRNG_CONFIG, NSAMPLE_CLOCKS);
+
+	while (len > 0) {
+		int i;
+
+		/* Start TRNG. */
+		mmio_write_32(TRNG_BASE + TRNG_CONTROL, 1);
+
+		/* Check if output is valid. */
+		if (!output_valid())
+			return -1;
+
+		/* Fill entropy buffer. */
+		for (i = 0; i < TRNG_NOUTPUTS; i++) {
+			size_t n;
+			uint32_t val;
+
+			val = mmio_read_32(TRNG_BASE + i * sizeof(uint32_t));
+			n = MIN(len, sizeof(uint32_t));
+			memcpy(bp, &val, n);
+			bp += n;
+			len -= n;
+			if (len == 0)
+				break;
+		}
+
+		/* Reset TRNG outputs. */
+		mmio_write_32(TRNG_BASE + TRNG_STATUS, 1);
+	}
+
+	return 0;
+}
diff --git a/platform/drivers/arm/juno_trng/juno_trng_adapter.c b/platform/drivers/arm/juno_trng/juno_trng_adapter.c
new file mode 100644
index 0000000..3ad8b04
--- /dev/null
+++ b/platform/drivers/arm/juno_trng/juno_trng_adapter.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <platform/interface/trng.h>
+#include <platform/interface/device_region.h>
+#include "juno_decl.h"
+
+/*
+ * A platform trng driver that uses the juno_trng driver from TF-A to provide a
+ * hardware entropy source.
+ */
+
+static int trng_poll(void *context, unsigned char *output, size_t nbyte, size_t *len)
+{
+     int status = 0;
+
+    *len = 0;
+
+    if (nbyte >= sizeof(unsigned char)) {
+
+        status = juno_getentropy(output, nbyte);
+
+        if (status == 0) {
+            *len = nbyte;
+        }
+        else {
+            /* Mbedtls currently crashes when a failure status is returned.
+             * This workaround prevents the crash for cases where no
+             * configuration has been provided for the trng.
+             */
+            status = 0;
+            *len = sizeof(unsigned char);
+        }
+    }
+
+    return status;
+}
+
+int platform_trng_create(struct platform_trng_driver *driver,
+                            const struct device_region *device_region)
+{
+    static const struct platform_trng_iface iface =  { .poll = trng_poll };
+
+    /*
+     * Default to leaving the driver in a safe but inoperable state.
+     */
+    driver->iface = &iface;
+    driver->context = NULL;
+
+    if (device_region) {
+
+        /*
+         * A device region has been provided, possibly from an external configuation.
+         */
+        juno_trng_set_base_addr(device_region->base_addr);
+    }
+
+    return 0;
+}
+
+void platform_trng_destroy(struct platform_trng_driver *driver)
+{
+    (void)driver;
+    juno_trng_set_base_addr(0);
+}
diff --git a/platform/drivers/arm/juno_trng/mmio.h b/platform/drivers/arm/juno_trng/mmio.h
new file mode 100644
index 0000000..da8d82f
--- /dev/null
+++ b/platform/drivers/arm/juno_trng/mmio.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copied from trustedfirmware-a and stripped down to only provide functions
+ * used by juno_trng.c.
+ */
+
+#ifndef MMIO_H
+#define MMIO_H
+
+#include <stdint.h>
+
+
+static inline void mmio_write_32(uintptr_t addr, uint32_t value)
+{
+	*(volatile uint32_t*)addr = value;
+}
+
+static inline uint32_t mmio_read_32(uintptr_t addr)
+{
+	return *(volatile uint32_t*)addr;
+}
+
+#endif /* MMIO_H */
diff --git a/platform/drivers/arm/tztrng/driver.cmake b/platform/drivers/arm/tztrng/driver.cmake
index 58d98c8..6a7f936 100644
--- a/platform/drivers/arm/tztrng/driver.cmake
+++ b/platform/drivers/arm/tztrng/driver.cmake
@@ -65,4 +65,4 @@
 add_dependencies(${TGT} libcc_tztrng)
 
 # Add adapter to map platform trng interface to tz-trng driver
-target_sources(${TGT} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/tztrng_trng.c")
+target_sources(${TGT} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/tztrng_adapter.c")
diff --git a/platform/drivers/arm/tztrng/tztrng_trng.c b/platform/drivers/arm/tztrng/tztrng_adapter.c
similarity index 100%
rename from platform/drivers/arm/tztrng/tztrng_trng.c
rename to platform/drivers/arm/tztrng/tztrng_adapter.c
diff --git a/platform/interface/device_region.h b/platform/interface/device_region.h
index 1ad1721..8bbf203 100644
--- a/platform/interface/device_region.h
+++ b/platform/interface/device_region.h
@@ -23,7 +23,7 @@
 {
     char dev_class[16];     /**< Identifier for class of device e.g. 'trng' */
     int dev_instance;       /**< Instance of the class of device on a platform */
-    uint8_t *base_addr;     /**< Base address or region */
+    uintptr_t base_addr;    /**< Base address or region */
     size_t io_region_size;  /**< Size of I/O region in bytes */
 };
 
diff --git a/platform/providers/arm/fvp/fvp_base_revc-2xaemv8a/platform.cmake b/platform/providers/arm/fvp/fvp_base_revc-2xaemv8a/platform.cmake
index cb01389..ff7c049 100644
--- a/platform/providers/arm/fvp/fvp_base_revc-2xaemv8a/platform.cmake
+++ b/platform/providers/arm/fvp/fvp_base_revc-2xaemv8a/platform.cmake
@@ -18,5 +18,5 @@
 #
 #-------------------------------------------------------------------------------
 if ("trng" IN_LIST _platform_driver_dependencies)
-	include(${TS_ROOT}/platform/drivers/arm/tztrng/driver.cmake)
+	include(${TS_ROOT}/platform/drivers/arm/juno_trng/driver.cmake)
 endif()