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