174c676beSVesa Jääskeläinen // SPDX-License-Identifier: BSD-2-Clause
274c676beSVesa Jääskeläinen /*
374c676beSVesa Jääskeläinen * Copyright (c) 2022, Vaisala Oyj
474c676beSVesa Jääskeläinen */
574c676beSVesa Jääskeläinen
674c676beSVesa Jääskeläinen #include <assert.h>
774c676beSVesa Jääskeläinen #include <io.h>
874c676beSVesa Jääskeläinen #include <kernel/boot.h>
974c676beSVesa Jääskeläinen #include <kernel/delay.h>
1074c676beSVesa Jääskeläinen #include <kernel/dt.h>
1174c676beSVesa Jääskeläinen #include <kernel/dt_driver.h>
1274c676beSVesa Jääskeläinen #include <kernel/spinlock.h>
1374c676beSVesa Jääskeläinen #include <libfdt.h>
1474c676beSVesa Jääskeläinen #include <platform_config.h>
1574c676beSVesa Jääskeläinen #include <rng_support.h>
1674c676beSVesa Jääskeläinen #include <string.h>
1774c676beSVesa Jääskeläinen #include <tee/tee_cryp_utl.h>
1874c676beSVesa Jääskeläinen
1974c676beSVesa Jääskeläinen #define CONTROL_REG 0x00000000
2074c676beSVesa Jääskeläinen #define STATUS_REG 0x00000004
2174c676beSVesa Jääskeläinen #define RAND_REG 0x00000000
2274c676beSVesa Jääskeläinen
2374c676beSVesa Jääskeläinen #define HOST_TO_TRNG_RESET 0x00000001
2474c676beSVesa Jääskeläinen #define HOST_TO_TRNG_RELEASE_RESET 0x00000002
2574c676beSVesa Jääskeläinen #define HOST_TO_TRNG_ENABLE 0x80000000
2674c676beSVesa Jääskeläinen #define HOST_TO_TRNG_ZEROIZE 0x80000004
2774c676beSVesa Jääskeläinen #define HOST_TO_TRNG_ACK_ZEROIZE 0x80000008
2874c676beSVesa Jääskeläinen #define HOST_TO_TRNG_READ 0x8000000F
2974c676beSVesa Jääskeläinen
3074c676beSVesa Jääskeläinen /* trng statuses */
3174c676beSVesa Jääskeläinen #define TRNG_ACK_RESET 0x000000AC
3274c676beSVesa Jääskeläinen #define TRNG_SUCCESSFUL_STARTUP 0x00000057
3374c676beSVesa Jääskeläinen #define TRNG_FAILED_STARTUP 0x000000FA
3474c676beSVesa Jääskeläinen #define TRNG_NEW_RAND_AVAILABLE 0x000000ED
3574c676beSVesa Jääskeläinen
3674c676beSVesa Jääskeläinen static unsigned int trng_lock = SPINLOCK_UNLOCK;
3774c676beSVesa Jääskeläinen
3874c676beSVesa Jääskeläinen static vaddr_t xiphera_trng_base;
3974c676beSVesa Jääskeläinen
xiphera_trng_random_available(void)40825dff97SVesa Jääskeläinen static bool xiphera_trng_random_available(void)
41825dff97SVesa Jääskeläinen {
42825dff97SVesa Jääskeläinen uint32_t status = 0;
43825dff97SVesa Jääskeläinen
44825dff97SVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG);
45825dff97SVesa Jääskeläinen
46825dff97SVesa Jääskeläinen return status == TRNG_NEW_RAND_AVAILABLE;
47825dff97SVesa Jääskeläinen }
48825dff97SVesa Jääskeläinen
xiphera_trng_read32(void)4974c676beSVesa Jääskeläinen static uint32_t xiphera_trng_read32(void)
5074c676beSVesa Jääskeläinen {
5174c676beSVesa Jääskeläinen uint32_t value = 0;
5274c676beSVesa Jääskeläinen
5374c676beSVesa Jääskeläinen value = io_read32(xiphera_trng_base + RAND_REG);
5474c676beSVesa Jääskeläinen
5574c676beSVesa Jääskeläinen /*
56825dff97SVesa Jääskeläinen * Ack that RNG value has been consumed and trigger new one to be
57825dff97SVesa Jääskeläinen * generated
5874c676beSVesa Jääskeläinen */
5974c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_READ);
60825dff97SVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ENABLE);
6174c676beSVesa Jääskeläinen
6274c676beSVesa Jääskeläinen return value;
6374c676beSVesa Jääskeläinen }
6474c676beSVesa Jääskeläinen
6574c676beSVesa Jääskeläinen /* This is a true RNG, no need for seeding */
plat_rng_init(void)6674c676beSVesa Jääskeläinen void plat_rng_init(void)
6774c676beSVesa Jääskeläinen {
6874c676beSVesa Jääskeläinen }
6974c676beSVesa Jääskeläinen
hw_get_random_bytes(void * buf,size_t len)70bc842791SAndrew Davis TEE_Result hw_get_random_bytes(void *buf, size_t len)
7174c676beSVesa Jääskeläinen {
72825dff97SVesa Jääskeläinen uint8_t *rngbuf = buf;
73825dff97SVesa Jääskeläinen uint32_t val = 0;
74825dff97SVesa Jääskeläinen size_t len_to_copy = 0;
7574c676beSVesa Jääskeläinen
76825dff97SVesa Jääskeläinen assert(buf);
7774c676beSVesa Jääskeläinen assert(xiphera_trng_base);
7874c676beSVesa Jääskeläinen
79825dff97SVesa Jääskeläinen while (len) {
80bc842791SAndrew Davis uint32_t exceptions = cpu_spin_lock_xsave(&trng_lock);
81bc842791SAndrew Davis
82825dff97SVesa Jääskeläinen if (xiphera_trng_random_available()) {
83825dff97SVesa Jääskeläinen val = xiphera_trng_read32();
84bc842791SAndrew Davis
85825dff97SVesa Jääskeläinen len_to_copy = MIN(len, sizeof(uint32_t));
86825dff97SVesa Jääskeläinen memcpy(rngbuf, &val, len_to_copy);
87825dff97SVesa Jääskeläinen rngbuf += len_to_copy;
88825dff97SVesa Jääskeläinen len -= len_to_copy;
89825dff97SVesa Jääskeläinen }
90bc842791SAndrew Davis
91bc842791SAndrew Davis cpu_spin_unlock_xrestore(&trng_lock, exceptions);
9274c676beSVesa Jääskeläinen }
9374c676beSVesa Jääskeläinen
9474c676beSVesa Jääskeläinen return TEE_SUCCESS;
9574c676beSVesa Jääskeläinen }
9674c676beSVesa Jääskeläinen
xiphera_trng_probe(const void * fdt,int node,const void * compat_data __unused)9774c676beSVesa Jääskeläinen static TEE_Result xiphera_trng_probe(const void *fdt, int node,
9874c676beSVesa Jääskeläinen const void *compat_data __unused)
9974c676beSVesa Jääskeläinen {
100f354a5d8SGatien Chevallier int dt_status = fdt_get_status(fdt, node);
10174c676beSVesa Jääskeläinen uint32_t status = 0;
10274c676beSVesa Jääskeläinen size_t size = 0;
10374c676beSVesa Jääskeläinen
10474c676beSVesa Jääskeläinen /* Skip non-secure instances */
10574c676beSVesa Jääskeläinen if (dt_status != DT_STATUS_OK_SEC)
10674c676beSVesa Jääskeläinen return TEE_ERROR_NODE_DISABLED;
10774c676beSVesa Jääskeläinen
10874c676beSVesa Jääskeläinen if (xiphera_trng_base) {
10974c676beSVesa Jääskeläinen EMSG("Only one secure instance is supported");
11074c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC;
11174c676beSVesa Jääskeläinen }
11274c676beSVesa Jääskeläinen
113a5d5bbc8SVesa Jääskeläinen if (dt_map_dev(fdt, node, &xiphera_trng_base, &size, DT_MAP_AUTO) < 0)
11474c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC;
11574c676beSVesa Jääskeläinen
11674c676beSVesa Jääskeläinen /*
11774c676beSVesa Jääskeläinen * The TRNG needs to be first reset in order to provide stable
11874c676beSVesa Jääskeläinen * operation.
11974c676beSVesa Jääskeläinen *
12074c676beSVesa Jääskeläinen * Reset of the chip should complete within 200 us but in some cases it
12174c676beSVesa Jääskeläinen * could take up to 400 us. If it is not ready within 400 us assume
12274c676beSVesa Jääskeläinen * there is problem.
12374c676beSVesa Jääskeläinen */
12474c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_RESET);
12574c676beSVesa Jääskeläinen udelay(200);
12674c676beSVesa Jääskeläinen
12774c676beSVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG);
12874c676beSVesa Jääskeläinen if (status != TRNG_ACK_RESET) {
12974c676beSVesa Jääskeläinen /*
13074c676beSVesa Jääskeläinen * Give it additional 200 us to allow it to reset.
13174c676beSVesa Jääskeläinen *
13274c676beSVesa Jääskeläinen * If still not done -> error out.
13374c676beSVesa Jääskeläinen */
13474c676beSVesa Jääskeläinen udelay(200);
13574c676beSVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG);
13674c676beSVesa Jääskeläinen if (status != TRNG_ACK_RESET) {
137*bce2f88aSVincent Mailhol EMSG("Failed to reset TRNG");
13874c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC;
13974c676beSVesa Jääskeläinen }
14074c676beSVesa Jääskeläinen }
14174c676beSVesa Jääskeläinen
14274c676beSVesa Jääskeläinen /*
14374c676beSVesa Jääskeläinen * Now TRNG should be internally stable.
14474c676beSVesa Jääskeläinen *
14574c676beSVesa Jääskeläinen * Clear internal random number generation engine to start in stable
14674c676beSVesa Jääskeläinen * state and give it 20 ms to enable good random number entropy and
14774c676beSVesa Jääskeläinen * then check that random number engine is ready.
14874c676beSVesa Jääskeläinen */
14974c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG,
15074c676beSVesa Jääskeläinen HOST_TO_TRNG_RELEASE_RESET);
15174c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ENABLE);
15274c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ZEROIZE);
15374c676beSVesa Jääskeläinen mdelay(20);
15474c676beSVesa Jääskeläinen
15574c676beSVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG);
15674c676beSVesa Jääskeläinen if (status != TRNG_SUCCESSFUL_STARTUP) {
15774c676beSVesa Jääskeläinen /*
15874c676beSVesa Jääskeläinen * Check specifically if there were startup test errors to aid
15974c676beSVesa Jääskeläinen * in debugging TRNG implementation in FPGA
16074c676beSVesa Jääskeläinen */
16174c676beSVesa Jääskeläinen if (status == TRNG_FAILED_STARTUP) {
162*bce2f88aSVincent Mailhol EMSG("Startup tests have failed");
16374c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC;
16474c676beSVesa Jääskeläinen }
16574c676beSVesa Jääskeläinen
166*bce2f88aSVincent Mailhol EMSG("Startup tests yielded no response -> TRNG stuck");
16774c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC;
16874c676beSVesa Jääskeläinen }
16974c676beSVesa Jääskeläinen
17074c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ACK_ZEROIZE);
17174c676beSVesa Jääskeläinen
172*bce2f88aSVincent Mailhol DMSG("TRNG initialized");
17374c676beSVesa Jääskeläinen
17474c676beSVesa Jääskeläinen return TEE_SUCCESS;
17574c676beSVesa Jääskeläinen }
17674c676beSVesa Jääskeläinen
17774c676beSVesa Jääskeläinen static const struct dt_device_match xiphera_trng_match_table[] = {
17874c676beSVesa Jääskeläinen { .compatible = "xiphera,xip8001b-trng" },
17974c676beSVesa Jääskeläinen { }
18074c676beSVesa Jääskeläinen };
18174c676beSVesa Jääskeläinen
18274c676beSVesa Jääskeläinen DEFINE_DT_DRIVER(xiphera_trng_dt_driver) = {
18374c676beSVesa Jääskeläinen .name = "xiphera_trng",
18474c676beSVesa Jääskeläinen .type = DT_DRIVER_NOTYPE,
18574c676beSVesa Jääskeläinen .match_table = xiphera_trng_match_table,
18674c676beSVesa Jääskeläinen .probe = xiphera_trng_probe,
18774c676beSVesa Jääskeläinen };
188