1 /*
2 * Copyright (c) 2019, STMicroelectronics - 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 <libfdt.h>
12
13 #include <platform_def.h>
14
15 #include <arch_helpers.h>
16 #include <common/debug.h>
17 #include <drivers/delay_timer.h>
18 #include <drivers/st/stm32_hash.h>
19 #include <drivers/st/stm32mp_reset.h>
20 #include <lib/mmio.h>
21 #include <lib/utils.h>
22 #include <plat/common/platform.h>
23
24 #define DT_HASH_COMPAT "st,stm32f756-hash"
25
26 #define HASH_CR 0x00U
27 #define HASH_DIN 0x04U
28 #define HASH_STR 0x08U
29 #define HASH_SR 0x24U
30 #define HASH_HREG(x) (0x310U + ((x) * 0x04U))
31
32 /* Control Register */
33 #define HASH_CR_INIT BIT(2)
34 #define HASH_CR_DATATYPE_SHIFT U(4)
35
36 #define HASH_CR_ALGO_SHA1 0x0U
37 #define HASH_CR_ALGO_MD5 BIT(7)
38 #define HASH_CR_ALGO_SHA224 BIT(18)
39 #define HASH_CR_ALGO_SHA256 (BIT(18) | BIT(7))
40
41 /* Status Flags */
42 #define HASH_SR_DCIS BIT(1)
43 #define HASH_SR_BUSY BIT(3)
44
45 /* STR Register */
46 #define HASH_STR_NBLW_MASK GENMASK(4, 0)
47 #define HASH_STR_DCAL BIT(8)
48
49 #define MD5_DIGEST_SIZE 16U
50 #define SHA1_DIGEST_SIZE 20U
51 #define SHA224_DIGEST_SIZE 28U
52 #define SHA256_DIGEST_SIZE 32U
53
54 #define HASH_TIMEOUT_US 10000U
55
56 enum stm32_hash_data_format {
57 HASH_DATA_32_BITS,
58 HASH_DATA_16_BITS,
59 HASH_DATA_8_BITS,
60 HASH_DATA_1_BIT
61 };
62
63 struct stm32_hash_instance {
64 uintptr_t base;
65 unsigned int clock;
66 size_t digest_size;
67 };
68
69 struct stm32_hash_remain {
70 uint32_t buffer;
71 size_t length;
72 };
73
74 /* Expect a single HASH peripheral */
75 static struct stm32_hash_instance stm32_hash;
76 static struct stm32_hash_remain stm32_remain;
77
hash_base(void)78 static uintptr_t hash_base(void)
79 {
80 return stm32_hash.base;
81 }
82
hash_wait_busy(void)83 static int hash_wait_busy(void)
84 {
85 uint64_t timeout = timeout_init_us(HASH_TIMEOUT_US);
86
87 while ((mmio_read_32(hash_base() + HASH_SR) & HASH_SR_BUSY) != 0U) {
88 if (timeout_elapsed(timeout)) {
89 ERROR("%s: busy timeout\n", __func__);
90 return -ETIMEDOUT;
91 }
92 }
93
94 return 0;
95 }
96
hash_wait_computation(void)97 static int hash_wait_computation(void)
98 {
99 uint64_t timeout = timeout_init_us(HASH_TIMEOUT_US);
100
101 while ((mmio_read_32(hash_base() + HASH_SR) & HASH_SR_DCIS) == 0U) {
102 if (timeout_elapsed(timeout)) {
103 ERROR("%s: busy timeout\n", __func__);
104 return -ETIMEDOUT;
105 }
106 }
107
108 return 0;
109 }
110
hash_write_data(uint32_t data)111 static int hash_write_data(uint32_t data)
112 {
113 int ret;
114
115 ret = hash_wait_busy();
116 if (ret != 0) {
117 return ret;
118 }
119
120 mmio_write_32(hash_base() + HASH_DIN, data);
121
122 return 0;
123 }
124
hash_hw_init(enum stm32_hash_algo_mode mode)125 static void hash_hw_init(enum stm32_hash_algo_mode mode)
126 {
127 uint32_t reg;
128
129 reg = HASH_CR_INIT | (HASH_DATA_8_BITS << HASH_CR_DATATYPE_SHIFT);
130
131 switch (mode) {
132 case HASH_MD5SUM:
133 reg |= HASH_CR_ALGO_MD5;
134 stm32_hash.digest_size = MD5_DIGEST_SIZE;
135 break;
136 case HASH_SHA1:
137 reg |= HASH_CR_ALGO_SHA1;
138 stm32_hash.digest_size = SHA1_DIGEST_SIZE;
139 break;
140 case HASH_SHA224:
141 reg |= HASH_CR_ALGO_SHA224;
142 stm32_hash.digest_size = SHA224_DIGEST_SIZE;
143 break;
144 /* Default selected algo is SHA256 */
145 case HASH_SHA256:
146 default:
147 reg |= HASH_CR_ALGO_SHA256;
148 stm32_hash.digest_size = SHA256_DIGEST_SIZE;
149 break;
150 }
151
152 mmio_write_32(hash_base() + HASH_CR, reg);
153 }
154
hash_get_digest(uint8_t * digest)155 static int hash_get_digest(uint8_t *digest)
156 {
157 int ret;
158 uint32_t i;
159 uint32_t dsg;
160
161 ret = hash_wait_computation();
162 if (ret != 0) {
163 return ret;
164 }
165
166 for (i = 0U; i < (stm32_hash.digest_size / sizeof(uint32_t)); i++) {
167 dsg = __builtin_bswap32(mmio_read_32(hash_base() +
168 HASH_HREG(i)));
169 memcpy(digest + (i * sizeof(uint32_t)), &dsg, sizeof(uint32_t));
170 }
171
172 #if defined(IMAGE_BL2)
173 /*
174 * Clean hardware context as HASH could be used later
175 * by non-secure software
176 */
177 hash_hw_init(HASH_SHA256);
178 #endif
179 return 0;
180 }
181
stm32_hash_update(const uint8_t * buffer,size_t length)182 int stm32_hash_update(const uint8_t *buffer, size_t length)
183 {
184 size_t remain_length = length;
185 int ret = 0;
186
187 if ((length == 0U) || (buffer == NULL)) {
188 return 0;
189 }
190
191 stm32mp_clk_enable(stm32_hash.clock);
192
193 if (stm32_remain.length != 0U) {
194 uint32_t copysize;
195
196 copysize = MIN((sizeof(uint32_t) - stm32_remain.length),
197 length);
198 memcpy(((uint8_t *)&stm32_remain.buffer) + stm32_remain.length,
199 buffer, copysize);
200 remain_length -= copysize;
201 buffer += copysize;
202 if (stm32_remain.length == sizeof(uint32_t)) {
203 ret = hash_write_data(stm32_remain.buffer);
204 if (ret != 0) {
205 goto exit;
206 }
207
208 zeromem(&stm32_remain, sizeof(stm32_remain));
209 }
210 }
211
212 while (remain_length / sizeof(uint32_t) != 0U) {
213 uint32_t tmp_buf;
214
215 memcpy(&tmp_buf, buffer, sizeof(uint32_t));
216 ret = hash_write_data(tmp_buf);
217 if (ret != 0) {
218 goto exit;
219 }
220
221 buffer += sizeof(uint32_t);
222 remain_length -= sizeof(uint32_t);
223 }
224
225 if (remain_length != 0U) {
226 assert(stm32_remain.length == 0U);
227
228 memcpy((uint8_t *)&stm32_remain.buffer, buffer, remain_length);
229 stm32_remain.length = remain_length;
230 }
231
232 exit:
233 stm32mp_clk_disable(stm32_hash.clock);
234
235 return ret;
236 }
237
stm32_hash_final(uint8_t * digest)238 int stm32_hash_final(uint8_t *digest)
239 {
240 int ret;
241
242 stm32mp_clk_enable(stm32_hash.clock);
243
244 if (stm32_remain.length != 0U) {
245 ret = hash_write_data(stm32_remain.buffer);
246 if (ret != 0) {
247 stm32mp_clk_disable(stm32_hash.clock);
248 return ret;
249 }
250
251 mmio_clrsetbits_32(hash_base() + HASH_STR, HASH_STR_NBLW_MASK,
252 8U * stm32_remain.length);
253 zeromem(&stm32_remain, sizeof(stm32_remain));
254 }
255
256 mmio_setbits_32(hash_base() + HASH_STR, HASH_STR_DCAL);
257
258 ret = hash_get_digest(digest);
259
260 stm32mp_clk_disable(stm32_hash.clock);
261
262 return ret;
263 }
264
stm32_hash_final_update(const uint8_t * buffer,uint32_t length,uint8_t * digest)265 int stm32_hash_final_update(const uint8_t *buffer, uint32_t length,
266 uint8_t *digest)
267 {
268 int ret;
269
270 ret = stm32_hash_update(buffer, length);
271 if (ret != 0) {
272 return ret;
273 }
274
275 return stm32_hash_final(digest);
276 }
277
stm32_hash_init(enum stm32_hash_algo_mode mode)278 void stm32_hash_init(enum stm32_hash_algo_mode mode)
279 {
280 stm32mp_clk_enable(stm32_hash.clock);
281
282 hash_hw_init(mode);
283
284 stm32mp_clk_disable(stm32_hash.clock);
285
286 zeromem(&stm32_remain, sizeof(stm32_remain));
287 }
288
stm32_hash_register(void)289 int stm32_hash_register(void)
290 {
291 struct dt_node_info hash_info;
292 int node;
293
294 for (node = dt_get_node(&hash_info, -1, DT_HASH_COMPAT);
295 node != -FDT_ERR_NOTFOUND;
296 node = dt_get_node(&hash_info, node, DT_HASH_COMPAT)) {
297 #if defined(IMAGE_BL2)
298 if (hash_info.status != DT_DISABLED) {
299 break;
300 }
301 #else
302 if (hash_info.status == DT_SECURE) {
303 break;
304 }
305 #endif
306 }
307
308 if (node == -FDT_ERR_NOTFOUND) {
309 return -ENODEV;
310 }
311
312 if (hash_info.clock < 0) {
313 return -EINVAL;
314 }
315
316 stm32_hash.base = hash_info.base;
317 stm32_hash.clock = hash_info.clock;
318
319 stm32mp_clk_enable(stm32_hash.clock);
320
321 if (hash_info.reset >= 0) {
322 stm32mp_reset_assert((unsigned long)hash_info.reset);
323 udelay(20);
324 stm32mp_reset_deassert((unsigned long)hash_info.reset);
325 }
326
327 stm32mp_clk_disable(stm32_hash.clock);
328
329 return 0;
330 }
331