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