blob: f72787d33f0da3929cf6d0f80791898cad5b7d18 [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
54#define HASH_TIMEOUT_US 10000U
55
56enum stm32_hash_data_format {
57 HASH_DATA_32_BITS,
58 HASH_DATA_16_BITS,
59 HASH_DATA_8_BITS,
60 HASH_DATA_1_BIT
61};
62
63struct stm32_hash_instance {
64 uintptr_t base;
65 unsigned int clock;
66 size_t digest_size;
67};
68
69struct stm32_hash_remain {
70 uint32_t buffer;
71 size_t length;
72};
73
74/* Expect a single HASH peripheral */
75static struct stm32_hash_instance stm32_hash;
76static struct stm32_hash_remain stm32_remain;
77
78static uintptr_t hash_base(void)
79{
80 return stm32_hash.base;
81}
82
83static int hash_wait_busy(void)
84{
85 uint64_t timeout = timeout_init_us(HASH_TIMEOUT_US);
86
87 while ((mmio_read_32(hash_base() + HASH_SR) & HASH_SR_BUSY) != 0U) {
88 if (timeout_elapsed(timeout)) {
89 ERROR("%s: busy timeout\n", __func__);
90 return -ETIMEDOUT;
91 }
92 }
93
94 return 0;
95}
96
97static int hash_wait_computation(void)
98{
99 uint64_t timeout = timeout_init_us(HASH_TIMEOUT_US);
100
101 while ((mmio_read_32(hash_base() + HASH_SR) & HASH_SR_DCIS) == 0U) {
102 if (timeout_elapsed(timeout)) {
103 ERROR("%s: busy timeout\n", __func__);
104 return -ETIMEDOUT;
105 }
106 }
107
108 return 0;
109}
110
111static int hash_write_data(uint32_t data)
112{
113 int ret;
114
115 ret = hash_wait_busy();
116 if (ret != 0) {
117 return ret;
118 }
119
120 mmio_write_32(hash_base() + HASH_DIN, data);
121
122 return 0;
123}
124
125static void hash_hw_init(enum stm32_hash_algo_mode mode)
126{
127 uint32_t reg;
128
129 reg = HASH_CR_INIT | (HASH_DATA_8_BITS << HASH_CR_DATATYPE_SHIFT);
130
131 switch (mode) {
132 case HASH_MD5SUM:
133 reg |= HASH_CR_ALGO_MD5;
134 stm32_hash.digest_size = MD5_DIGEST_SIZE;
135 break;
136 case HASH_SHA1:
137 reg |= HASH_CR_ALGO_SHA1;
138 stm32_hash.digest_size = SHA1_DIGEST_SIZE;
139 break;
140 case HASH_SHA224:
141 reg |= HASH_CR_ALGO_SHA224;
142 stm32_hash.digest_size = SHA224_DIGEST_SIZE;
143 break;
144 /* Default selected algo is SHA256 */
145 case HASH_SHA256:
146 default:
147 reg |= HASH_CR_ALGO_SHA256;
148 stm32_hash.digest_size = SHA256_DIGEST_SIZE;
149 break;
150 }
151
152 mmio_write_32(hash_base() + HASH_CR, reg);
153}
154
155static int hash_get_digest(uint8_t *digest)
156{
157 int ret;
158 uint32_t i;
159 uint32_t dsg;
160
161 ret = hash_wait_computation();
162 if (ret != 0) {
163 return ret;
164 }
165
166 for (i = 0U; i < (stm32_hash.digest_size / sizeof(uint32_t)); i++) {
167 dsg = __builtin_bswap32(mmio_read_32(hash_base() +
168 HASH_HREG(i)));
169 memcpy(digest + (i * sizeof(uint32_t)), &dsg, sizeof(uint32_t));
170 }
171
172#if defined(IMAGE_BL2)
173 /*
174 * Clean hardware context as HASH could be used later
175 * by non-secure software
176 */
177 hash_hw_init(HASH_SHA256);
178#endif
179 return 0;
180}
181
182int stm32_hash_update(const uint8_t *buffer, size_t length)
183{
184 size_t remain_length = length;
185 int ret = 0;
186
187 if ((length == 0U) || (buffer == NULL)) {
188 return 0;
189 }
190
191 stm32mp_clk_enable(stm32_hash.clock);
192
193 if (stm32_remain.length != 0U) {
194 uint32_t copysize;
195
196 copysize = MIN((sizeof(uint32_t) - stm32_remain.length),
197 length);
198 memcpy(((uint8_t *)&stm32_remain.buffer) + stm32_remain.length,
199 buffer, copysize);
200 remain_length -= copysize;
201 buffer += copysize;
202 if (stm32_remain.length == sizeof(uint32_t)) {
203 ret = hash_write_data(stm32_remain.buffer);
204 if (ret != 0) {
205 goto exit;
206 }
207
208 zeromem(&stm32_remain, sizeof(stm32_remain));
209 }
210 }
211
212 while (remain_length / sizeof(uint32_t) != 0U) {
213 uint32_t tmp_buf;
214
215 memcpy(&tmp_buf, buffer, sizeof(uint32_t));
216 ret = hash_write_data(tmp_buf);
217 if (ret != 0) {
218 goto exit;
219 }
220
221 buffer += sizeof(uint32_t);
222 remain_length -= sizeof(uint32_t);
223 }
224
225 if (remain_length != 0U) {
226 assert(stm32_remain.length == 0U);
227
228 memcpy((uint8_t *)&stm32_remain.buffer, buffer, remain_length);
229 stm32_remain.length = remain_length;
230 }
231
232exit:
233 stm32mp_clk_disable(stm32_hash.clock);
234
235 return ret;
236}
237
238int stm32_hash_final(uint8_t *digest)
239{
240 int ret;
241
242 stm32mp_clk_enable(stm32_hash.clock);
243
244 if (stm32_remain.length != 0U) {
245 ret = hash_write_data(stm32_remain.buffer);
246 if (ret != 0) {
247 stm32mp_clk_disable(stm32_hash.clock);
248 return ret;
249 }
250
251 mmio_clrsetbits_32(hash_base() + HASH_STR, HASH_STR_NBLW_MASK,
252 8U * stm32_remain.length);
253 zeromem(&stm32_remain, sizeof(stm32_remain));
254 }
255
256 mmio_setbits_32(hash_base() + HASH_STR, HASH_STR_DCAL);
257
258 ret = hash_get_digest(digest);
259
260 stm32mp_clk_disable(stm32_hash.clock);
261
262 return ret;
263}
264
265int stm32_hash_final_update(const uint8_t *buffer, uint32_t length,
266 uint8_t *digest)
267{
268 int ret;
269
270 ret = stm32_hash_update(buffer, length);
271 if (ret != 0) {
272 return ret;
273 }
274
275 return stm32_hash_final(digest);
276}
277
278void stm32_hash_init(enum stm32_hash_algo_mode mode)
279{
280 stm32mp_clk_enable(stm32_hash.clock);
281
282 hash_hw_init(mode);
283
284 stm32mp_clk_disable(stm32_hash.clock);
285
286 zeromem(&stm32_remain, sizeof(stm32_remain));
287}
288
289int stm32_hash_register(void)
290{
291 struct dt_node_info hash_info;
292 int node;
293
294 for (node = dt_get_node(&hash_info, -1, DT_HASH_COMPAT);
295 node != -FDT_ERR_NOTFOUND;
296 node = dt_get_node(&hash_info, node, DT_HASH_COMPAT)) {
297#if defined(IMAGE_BL2)
298 if (hash_info.status != DT_DISABLED) {
299 break;
300 }
301#else
302 if (hash_info.status == DT_SECURE) {
303 break;
304 }
305#endif
306 }
307
308 if (node == -FDT_ERR_NOTFOUND) {
309 return -ENODEV;
310 }
311
312 if (hash_info.clock < 0) {
313 return -EINVAL;
314 }
315
316 stm32_hash.base = hash_info.base;
317 stm32_hash.clock = hash_info.clock;
318
319 stm32mp_clk_enable(stm32_hash.clock);
320
321 if (hash_info.reset >= 0) {
322 stm32mp_reset_assert((unsigned long)hash_info.reset);
323 udelay(20);
324 stm32mp_reset_deassert((unsigned long)hash_info.reset);
325 }
326
327 stm32mp_clk_disable(stm32_hash.clock);
328
329 return 0;
330}