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_byte(void)65 uint8_t hw_get_random_byte(void)
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 	uint8_t ret;
74 	uint32_t exceptions;
75 
76 	exceptions = cpu_spin_lock_xsave(&rng_lock);
77 
78 	if (!r)
79 		r = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC, 1) +
80 			RNG_NUM;
81 
82 	if (!pos)
83 		random.val = io_read32(r);
84 
85 	ret = random.byte[pos++];
86 
87 	if (pos == 4)
88 		pos = 0;
89 
90 	cpu_spin_unlock_xrestore(&rng_lock, exceptions);
91 
92 	return ret;
93 }
94 
95 driver_init(hi16xx_rng_init);
96