• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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