1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2016, Linaro Limited
4 */
5
6 /* Driver for the internal Random Number Generator of HiSilicon P660/Hi16xx */
7
8 #include <initcall.h>
9 #include <io.h>
10 #include <kernel/spinlock.h>
11 #include <kernel/tee_time.h>
12 #include <mm/core_memprot.h>
13 #include <mm/core_mmu.h>
14 #include <platform_config.h>
15 #include <rng_support.h>
16 #include <trace.h>
17 #include <types_ext.h>
18 #include <util.h>
19
20 /* ALG sub-controller registers */
21
22 #define ALG_SC_RNG_RESET_DREQ 0xAB4 /* RNG reset cancel */
23 # define ALG_SC_SRST_DREQ_RNG BIT(0)
24
25 /* RNG registers */
26
27 #define RNG_SEED 0x0 /* Initial seed */
28 #define RNG_CTRL 0x4 /* Control register */
29 # define RNG_SEED_SEL BIT(2) /* Re-seed source: 1: ring osc., 0: LFSR */
30 # define RNG_RING_EN BIT(1) /* Enable ring oscillator */
31 # define RNG_EN BIT(0) /* Enable RNG */
32 #define RNG_NUM 0x10 /* Random number output */
33 #define RNG_PHY_SEED 0x14 /* Ring oscillator output */
34
35 register_phys_mem_pgdir(MEM_AREA_IO_SEC, ALG_SC_BASE, ALG_SC_REG_SIZE);
36 register_phys_mem_pgdir(MEM_AREA_IO_SEC, RNG_BASE, RNG_REG_SIZE);
37
38 static unsigned int rng_lock = SPINLOCK_UNLOCK;
39
hi16xx_rng_init(void)40 static TEE_Result hi16xx_rng_init(void)
41 {
42 vaddr_t alg = (vaddr_t)phys_to_virt(ALG_SC_BASE, MEM_AREA_IO_SEC,
43 ALG_SC_REG_SIZE);
44 vaddr_t rng = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC,
45 RNG_REG_SIZE);
46 TEE_Time time;
47
48 /* ALG sub-controller must allow RNG out of reset */
49 io_write32(alg + ALG_SC_RNG_RESET_DREQ, ALG_SC_SRST_DREQ_RNG);
50
51 /* Set initial seed */
52 tee_time_get_sys_time(&time);
53 io_write32(rng + RNG_SEED, time.seconds * 1000 + time.millis);
54
55 /*
56 * Enable RNG and configure it to re-seed automatically from the
57 * internal ring oscillator
58 */
59 io_write32(rng + RNG_CTRL, RNG_EN | RNG_RING_EN | RNG_SEED_SEL);
60
61 IMSG("Hi16xx RNG initialized");
62 return TEE_SUCCESS;
63 }
64
hw_get_random_bytes(void * buf,size_t len)65 TEE_Result hw_get_random_bytes(void *buf, size_t len)
66 {
67 static vaddr_t r;
68 static int pos;
69 static union {
70 uint32_t val;
71 uint8_t byte[4];
72 } random;
73 size_t buffer_pos = 0;
74 uint8_t *buffer = buf;
75 uint32_t exceptions;
76
77 exceptions = cpu_spin_lock_xsave(&rng_lock);
78 if (!r)
79 r = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC, 1) +
80 RNG_NUM;
81 cpu_spin_unlock_xrestore(&rng_lock, exceptions);
82
83 while (buffer_pos < len) {
84 exceptions = cpu_spin_lock_xsave(&rng_lock);
85
86 /* Refill our FIFO */
87 if (pos == 0)
88 random.val = io_read32(r);
89
90 buffer[buffer_pos++] = random.byte[pos++];
91 if (pos == 4)
92 pos = 0;
93
94 cpu_spin_unlock_xrestore(&rng_lock, exceptions);
95 }
96
97 return TEE_SUCCESS;
98 }
99
100 driver_init(hi16xx_rng_init);
101