1 /*
2 * Copyright (c) 2024, MediaTek Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <stdint.h>
10
11 #include <common/debug.h>
12 #include <drivers/delay_timer.h>
13 #include <lib/mmio.h>
14 #include <lib/smccc.h>
15 #include <lib/spinlock.h>
16 #include <plat/common/platform.h>
17 #include <platform_def.h>
18 #include <services/trng_svc.h>
19 #include <smccc_helpers.h>
20
21 #include <mtk_mmap_pool.h>
22 #include <mtk_sip_svc.h>
23 #include "rng_plat.h"
24
25 static spinlock_t rng_lock;
26
trng_wait(uint32_t reg,uint32_t expected_value)27 static int trng_wait(uint32_t reg, uint32_t expected_value)
28 {
29 uint64_t timeout = timeout_init_us(TRNG_TIME_OUT);
30 uint32_t value = 0;
31
32 do {
33 value = mmio_read_32(reg);
34 if ((value & expected_value) == expected_value)
35 return 0;
36
37 udelay(10);
38 } while (!timeout_elapsed(timeout));
39
40 return -ETIMEDOUT;
41 }
42
trng_write(uint32_t reg,uint32_t value,uint32_t read_reg,uint32_t expected_value)43 static int trng_write(uint32_t reg, uint32_t value,
44 uint32_t read_reg, uint32_t expected_value)
45 {
46 int retry = MTK_TRNG_MAX_ROUND;
47 uint32_t read_value = 0;
48
49 do {
50 mmio_write_32(reg, value);
51
52 read_value = mmio_read_32(read_reg);
53 if ((read_value & value) == expected_value)
54 return 0;
55
56 udelay(10);
57 } while (--retry > 0);
58
59 return -ETIMEDOUT;
60 }
61
trng_prng(uint32_t * rand)62 static uint32_t trng_prng(uint32_t *rand)
63 {
64 int32_t ret = 0;
65 uint32_t seed[4] = {0};
66
67 if (rand == NULL)
68 return MTK_SIP_E_INVALID_PARAM;
69
70 /* ungate */
71 ret = trng_write(TRNG_PDN_CLR, TRNG_PDN_VALUE, TRNG_PDN_STATUS, 0);
72 if (ret) {
73 ERROR("%s: ungate fail\n", __func__);
74 return MTK_SIP_E_NOT_SUPPORTED;
75 }
76
77 /* read random data once and drop it */
78 seed[0] = mmio_read_32(TRNG_DATA);
79
80 /* enable von-neumann extractor */
81 mmio_setbits_32(TRNG_CONF, TRNG_CONF_VON_EN);
82
83 /* start */
84 mmio_setbits_32(TRNG_CTRL, TRNG_CTRL_START);
85
86 /* get seeds from trng */
87 for (int i = 0; i < ARRAY_SIZE(seed); i++) {
88 ret = trng_wait(TRNG_CTRL, TRNG_CTRL_RDY);
89 if (ret) {
90 ERROR("%s: trng NOT ready\n", __func__);
91 return MTK_SIP_E_NOT_SUPPORTED;
92 }
93
94 seed[i] = mmio_read_32(TRNG_DATA);
95 }
96
97 /* stop */
98 mmio_clrbits_32(TRNG_CTRL, TRNG_CTRL_START);
99
100 /* gate */
101 ret = trng_write(TRNG_PDN_SET, TRNG_PDN_VALUE, TRNG_PDN_STATUS, TRNG_PDN_VALUE);
102 if (ret) {
103 ERROR("%s: gate fail\n", __func__);
104 return MTK_SIP_E_NOT_SUPPORTED;
105 }
106
107 for (int i = 0; i < ARRAY_SIZE(seed); i++)
108 rand[i] = seed[i];
109
110 return 0;
111 }
112
get_true_rnd(uint32_t * val,uint32_t num)113 static uint32_t get_true_rnd(uint32_t *val, uint32_t num)
114 {
115 uint32_t rand[4] = {0};
116 uint32_t ret;
117
118 if (val == NULL || num > ARRAY_SIZE(rand))
119 return MTK_SIP_E_INVALID_PARAM;
120
121 spin_lock(&rng_lock);
122 ret = trng_prng(rand);
123 spin_unlock(&rng_lock);
124
125 for (int i = 0; i < num; i++)
126 val[i] = rand[i];
127
128 return ret;
129 }
130
131 /*
132 * plat_get_entropy - get 64-bit random number data which is used form
133 * atf early stage
134 * output - out: output 64-bit entropy combine with 2 32-bit random number
135 */
plat_get_entropy(uint64_t * out)136 bool plat_get_entropy(uint64_t *out)
137 {
138 uint32_t entropy_pool[2] = {0};
139 uint32_t ret;
140
141 assert(out);
142 assert(!check_uptr_overflow((uintptr_t)out, sizeof(*out)));
143
144 /* Get 2 32-bits entropy */
145 ret = get_true_rnd(entropy_pool, ARRAY_SIZE(entropy_pool));
146 if (ret)
147 return false;
148
149 /* Output 8 bytes entropy combine with 2 32-bit random number. */
150 *out = ((uint64_t)entropy_pool[0] << 32) | entropy_pool[1];
151
152 return true;
153 }
154