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