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