blob: 515947c103e05180b469afec7208fcc5d8cf7a78 [file] [log] [blame]
Lionel Debieve8cc21ea2019-08-26 15:14:51 +02001/*
2 * Copyright (c) 2019, 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
Etienne Carrieref02647a2019-12-08 08:14:40 +010054#define RESET_TIMEOUT_US_1MS 1000U
Lionel Debieve8cc21ea2019-08-26 15:14:51 +020055#define HASH_TIMEOUT_US 10000U
56
57enum 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
64struct stm32_hash_instance {
65 uintptr_t base;
66 unsigned int clock;
67 size_t digest_size;
68};
69
70struct stm32_hash_remain {
71 uint32_t buffer;
72 size_t length;
73};
74
75/* Expect a single HASH peripheral */
76static struct stm32_hash_instance stm32_hash;
77static struct stm32_hash_remain stm32_remain;
78
79static uintptr_t hash_base(void)
80{
81 return stm32_hash.base;
82}
83
84static 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
98static 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
112static 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
126static 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
156static 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
183int 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
233exit:
234 stm32mp_clk_disable(stm32_hash.clock);
235
236 return ret;
237}
238
239int 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 }
256
257 mmio_setbits_32(hash_base() + HASH_STR, HASH_STR_DCAL);
258
259 ret = hash_get_digest(digest);
260
261 stm32mp_clk_disable(stm32_hash.clock);
262
263 return ret;
264}
265
266int stm32_hash_final_update(const uint8_t *buffer, uint32_t length,
267 uint8_t *digest)
268{
269 int ret;
270
271 ret = stm32_hash_update(buffer, length);
272 if (ret != 0) {
273 return ret;
274 }
275
276 return stm32_hash_final(digest);
277}
278
279void stm32_hash_init(enum stm32_hash_algo_mode mode)
280{
281 stm32mp_clk_enable(stm32_hash.clock);
282
283 hash_hw_init(mode);
284
285 stm32mp_clk_disable(stm32_hash.clock);
286
287 zeromem(&stm32_remain, sizeof(stm32_remain));
288}
289
290int stm32_hash_register(void)
291{
292 struct dt_node_info hash_info;
293 int node;
294
295 for (node = dt_get_node(&hash_info, -1, DT_HASH_COMPAT);
296 node != -FDT_ERR_NOTFOUND;
297 node = dt_get_node(&hash_info, node, DT_HASH_COMPAT)) {
298#if defined(IMAGE_BL2)
299 if (hash_info.status != DT_DISABLED) {
300 break;
301 }
302#else
Etienne Carrieref8736282019-12-02 10:13:12 +0100303 /* BL32 uses hash if it is assigned only to secure world */
Lionel Debieve8cc21ea2019-08-26 15:14:51 +0200304 if (hash_info.status == DT_SECURE) {
Etienne Carrieref8736282019-12-02 10:13:12 +0100305 stm32mp_register_secure_periph_iomem(hash_info.base);
Lionel Debieve8cc21ea2019-08-26 15:14:51 +0200306 break;
307 }
308#endif
309 }
310
311 if (node == -FDT_ERR_NOTFOUND) {
312 return -ENODEV;
313 }
314
315 if (hash_info.clock < 0) {
316 return -EINVAL;
317 }
318
319 stm32_hash.base = hash_info.base;
320 stm32_hash.clock = hash_info.clock;
321
322 stm32mp_clk_enable(stm32_hash.clock);
323
324 if (hash_info.reset >= 0) {
Etienne Carrieref02647a2019-12-08 08:14:40 +0100325 uint32_t id = (uint32_t)hash_info.reset;
326
327 if (stm32mp_reset_assert(id, RESET_TIMEOUT_US_1MS) != 0) {
328 panic();
329 }
Lionel Debieve8cc21ea2019-08-26 15:14:51 +0200330 udelay(20);
Etienne Carrieref02647a2019-12-08 08:14:40 +0100331 if (stm32mp_reset_deassert(id, RESET_TIMEOUT_US_1MS) != 0) {
332 panic();
333 }
Lionel Debieve8cc21ea2019-08-26 15:14:51 +0200334 }
335
336 stm32mp_clk_disable(stm32_hash.clock);
337
338 return 0;
339}