summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJorge Ramirez-Ortiz <jorge@foundries.io>2021-02-23 16:46:42 +0100
committerJun Nie <jun.nie@linaro.org>2021-03-26 16:46:27 +0800
commit7661851aaa6c7095d6129c2625b9bbd36a06d9a6 (patch)
treec6bd87c2d76e33ceb9f613b3bc5ac0b6d8b7a3e0
parentb2c7fcc602ff0ee415c6ef97bbfa19ec666a70a1 (diff)
[FIO fromlist] drivers: imx_rngb: random number generator
Add support for the RNGB as described in the i.MX 6ULL Applications Processor Reference Manual, Rev 1, 11/2017. Tested on imx6ull based board. Signed-off-by: Jorge Ramirez-Ortiz <jorge@foundries.io> Signed-off-by: Ricardo Salveti <ricardo@foundries.io>
-rw-r--r--core/arch/arm/plat-imx/registers/imx6.h4
-rw-r--r--core/drivers/imx_rngb.c218
-rw-r--r--core/drivers/sub.mk1
3 files changed, 223 insertions, 0 deletions
diff --git a/core/arch/arm/plat-imx/registers/imx6.h b/core/arch/arm/plat-imx/registers/imx6.h
index 80ef0ac73..0c745884c 100644
--- a/core/arch/arm/plat-imx/registers/imx6.h
+++ b/core/arch/arm/plat-imx/registers/imx6.h
@@ -142,6 +142,10 @@
#define TRUSTZONE_OCRAM_START 0x938000
#endif
+#if defined(CFG_MX6SL) || defined(CFG_MX6SLL) || defined(CFG_MX6ULL)
+#define RNGB_BASE 0x2284000
+#endif
+
#ifdef CFG_MX6SL
#define DIGPROG_OFFSET 0x280
#else
diff --git a/core/drivers/imx_rngb.c b/core/drivers/imx_rngb.c
new file mode 100644
index 000000000..eaac39888
--- /dev/null
+++ b/core/drivers/imx_rngb.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * (c) 2021 Jorge Ramirez <jorge@foundries.io>, Foundries Ltd.
+ */
+
+#include <arm.h>
+#include <crypto/crypto.h>
+#include <initcall.h>
+#include <io.h>
+#include <kernel/boot.h>
+#include <kernel/delay.h>
+#include <kernel/dt.h>
+#include <kernel/panic.h>
+#include <libfdt.h>
+#include <mm/core_memprot.h>
+#include <mm/core_mmu.h>
+#include <platform_config.h>
+#include <rng_support.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tee/tee_cryp_utl.h>
+#include <trace.h>
+#include <util.h>
+
+#define RNGB_COMMAND 0x0004
+#define RNGB_CONTROL 0x0008
+#define RNGB_STATUS 0x000C
+#define RNGB_ERROR 0x0010
+#define RNGB_FIFO 0x0014
+
+#define RNGB_CMD_CLR_ERR 0x00000020
+#define RNGB_CMD_CLR_INT 0x00000010
+#define RNGB_CMD_SEED 0x00000002
+#define RNGB_CMD_SELF_TEST 0x00000001
+
+#define RNGB_CTRL_MASK_ERROR 0x00000040
+#define RNGB_CTRL_MASK_DONE 0x00000020
+
+#define RNGB_STATUS_ERROR 0x00010000
+#define RNGB_STATUS_FIFO_LEVEL_MASK 0x00000f00
+#define RNGB_STATUS_FIFO_LEVEL_SHIFT 8
+#define RNGB_STATUS_SEED_DONE 0x00000020
+#define RNGB_STATUS_ST_DONE 0x00000010
+
+#define RNGB_ERROR_STATUS_STAT_ERR 0x00000008
+
+static struct imx_rng {
+ struct io_pa_va base;
+ uint32_t error;
+} rngb = {
+#if !defined(CFG_DT) || defined(CFG_EXTERNAL_DTB_OVERLAY)
+#if defined(RNGB_BASE)
+ .base.pa = RNGB_BASE,
+#else
+#error IMX_RNGB driver not supported on this platform
+#endif
+#endif
+};
+
+static void wait_for_irq(struct imx_rng *rng)
+{
+ uint64_t tref = timeout_init_us(1000000);
+ uint32_t status = 0;
+
+ while (!timeout_elapsed(tref)) {
+ rng->error = io_read32(rng->base.va + RNGB_ERROR);
+ status = io_read32(rng->base.va + RNGB_STATUS);
+ if (status & (RNGB_STATUS_SEED_DONE | RNGB_STATUS_ST_DONE))
+ return;
+ }
+ panic();
+}
+
+static void irq_clear(struct imx_rng *rng)
+{
+ uint32_t ctrl = 0;
+ uint32_t cmd = 0;
+
+ ctrl = io_read32(rng->base.va + RNGB_CONTROL);
+ ctrl |= RNGB_CTRL_MASK_DONE | RNGB_CTRL_MASK_ERROR;
+ io_write32(rng->base.va + RNGB_CONTROL, ctrl);
+
+ cmd = io_read32(rng->base.va + RNGB_COMMAND);
+ cmd |= RNGB_CMD_CLR_INT | RNGB_CMD_CLR_ERR;
+ io_write32(rng->base.va + RNGB_COMMAND, cmd);
+}
+
+static void irq_unmask(struct imx_rng *rng)
+{
+ uint32_t ctrl = 0;
+
+ ctrl = io_read32(rng->base.va + RNGB_CONTROL);
+ ctrl &= ~(RNGB_CTRL_MASK_DONE | RNGB_CTRL_MASK_ERROR);
+ io_write32(rng->base.va + RNGB_CONTROL, ctrl);
+}
+
+static void rng_seed(struct imx_rng *rng)
+{
+ uint64_t tref = timeout_init_us(1000000);
+ uint32_t cmd = 0;
+
+ cmd = io_read32(rng->base.va + RNGB_COMMAND);
+ io_write32(rng->base.va + RNGB_COMMAND, cmd | RNGB_CMD_CLR_ERR);
+ do {
+ irq_unmask(rng);
+ cmd = io_read32(rng->base.va + RNGB_COMMAND);
+ io_write32(rng->base.va + RNGB_COMMAND, cmd | RNGB_CMD_SEED);
+ wait_for_irq(rng);
+ irq_clear(rng);
+ if (!rng->error)
+ return;
+ } while (!timeout_elapsed(tref));
+ panic();
+}
+
+#if defined(CFG_DT) && !defined(CFG_EXTERNAL_DTB_OVERLAY)
+static const char *const rng_match = "fsl,imx25-rngb";
+static TEE_Result map_controller(void)
+{
+ void *fdt = get_dt();
+ size_t size = 0;
+ int off = 0;
+
+ if (!fdt)
+ return TEE_ERROR_NOT_SUPPORTED;
+
+ off = fdt_node_offset_by_compatible(fdt, off, rng_match);
+ if (off < 0)
+ return TEE_ERROR_NOT_SUPPORTED;
+
+ if (dt_map_dev(fdt, off, &rngb.base.va, &size) < 0)
+ return TEE_ERROR_NOT_SUPPORTED;
+
+ rngb.base.pa = virt_to_phys((void *)rngb.base.va);
+
+ return TEE_SUCCESS;
+}
+#else
+
+static TEE_Result get_va(paddr_t pa, vaddr_t *va)
+{
+ if (!core_mmu_add_mapping(MEM_AREA_IO_SEC, pa, 0x4000))
+ return TEE_ERROR_GENERIC;
+
+ *va = (vaddr_t)phys_to_virt(pa, MEM_AREA_IO_SEC);
+ if (*va)
+ return TEE_SUCCESS;
+
+ return TEE_ERROR_GENERIC;
+}
+
+static TEE_Result map_controller(void)
+{
+ if (get_va(rngb.base.pa, &rngb.base.va))
+ return TEE_ERROR_GENERIC;
+
+ return TEE_SUCCESS;
+}
+#endif
+
+TEE_Result crypto_rng_read(void *buf, size_t len)
+{
+ uint32_t status = 0;
+ uint32_t words = 0;
+ uint32_t val = 0;
+ uint32_t *rngbuf = buf;
+
+ if (!rngb.base.va || !rngb.base.pa)
+ return TEE_ERROR_BAD_STATE;
+
+ while (len) {
+ status = io_read32(rngb.base.va + RNGB_STATUS);
+ if (status & RNGB_STATUS_ERROR)
+ return TEE_ERROR_BAD_STATE;
+
+ words = (status & RNGB_STATUS_FIFO_LEVEL_MASK) >>
+ RNGB_STATUS_FIFO_LEVEL_SHIFT;
+
+ if (words) {
+ val = io_read32(rngb.base.va + RNGB_FIFO);
+ if (len > sizeof(uint32_t)) {
+ len = len - sizeof(uint32_t);
+ memcpy(rngbuf, &val, sizeof(uint32_t));
+ rngbuf++;
+ } else {
+ memcpy(rngbuf, &val, len);
+ len = 0;
+ }
+ }
+ }
+
+ return TEE_SUCCESS;
+}
+
+uint8_t hw_get_random_byte(void)
+{
+ uint8_t data = 0;
+
+ if (crypto_rng_read(&data, 1))
+ panic();
+
+ return data;
+}
+
+void plat_rng_init(void)
+{
+}
+
+static TEE_Result rngb_init(void)
+{
+ if (map_controller())
+ panic();
+ rng_seed(&rngb);
+
+ return TEE_SUCCESS;
+}
+
+driver_init(rngb_init);
diff --git a/core/drivers/sub.mk b/core/drivers/sub.mk
index fc7acd2b3..d1202ecb1 100644
--- a/core/drivers/sub.mk
+++ b/core/drivers/sub.mk
@@ -35,6 +35,7 @@ srcs-$(CFG_IMX_SC) += imx_mu.c
srcs-$(CFG_CORE_SE05X) += scp03_pta.c
srcs-$(CFG_CORE_SE05X) += se050_cert_pta.c
srcs-$(CFG_RNG_PTA) += rng_pta.c
+srcs-$(CFG_IMX_RNGB) += imx_rngb.c
subdirs-y += crypto
subdirs-$(CFG_BNXT_FW) += bnxt