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