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