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