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