blob: 17cc30a7b54dfe1a70b71b376d33ce4796c0e64f [file] [log] [blame]
Johnny Huangd91aaa52021-10-27 14:17:27 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright 2021 ASPEED Technology Inc.
4 */
5#include <config.h>
Johnny Huangd91aaa52021-10-27 14:17:27 +08006#include <dm.h>
7#include <clk.h>
8#include <log.h>
9#include <asm/io.h>
10#include <malloc.h>
11#include <watchdog.h>
12#include <u-boot/hash.h>
13#include <linux/bitops.h>
14#include <linux/delay.h>
15#include <linux/kernel.h>
16#include <linux/iopoll.h>
17
18/* register offsets*/
19#define HACE_STS 0x1C
20#define HACE_HASH_DATA_OVF BIT(23)
21#define HACE_HASH_INT BIT(9)
22#define HACE_HASH_BUSY BIT(0)
23#define HACE_HASH_DATA 0x20
24#define HACE_HASH_DIGEST 0x24
25#define HACE_HASH_HMAC_KEY 0x28
26#define HACE_HASH_DATA_LEN 0x2C
27#define HACE_HASH_CMD 0x30
28#define HACE_HASH_MODE_ACCUM BIT(8)
29#define HACE_HASH_ALGO_SHA1 BIT(5)
30#define HACE_HASH_ALGO_SHA256 (BIT(6) | BIT(4))
31#define HACE_HASH_ALGO_SHA384 (BIT(10) | BIT(6) | BIT(5))
32#define HACE_HASH_ALGO_SHA512 (BIT(6) | BIT(5))
33#define HACE_HASH_SHA_BE_EN BIT(3)
34
35/* buffer size based on SHA-512 need*/
36#define HASH_BLOCK_BUFSZ 128
37#define HASH_DIGEST_BUFSZ 64
38
39struct aspeed_hace_ctx {
40 uint8_t digest[HASH_DIGEST_BUFSZ];
41
42 uint32_t cmd;
43 enum HASH_ALGO algo;
44
45 uint32_t blk_size;
46 uint32_t pad_size;
47 uint64_t total[2];
48
49 uint8_t buf[HASH_BLOCK_BUFSZ];
50 uint32_t buf_cnt;
51} __aligned((8));
52
53struct aspeed_hace {
54 phys_addr_t base;
55 struct clk clk;
56};
57
58static const uint32_t iv_sha1[8] = {
59 0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210,
60 0xf0e1d2c3, 0, 0, 0
61};
62
63static const uint32_t iv_sha256[8] = {
64 0x67e6096a, 0x85ae67bb, 0x72f36e3c, 0x3af54fa5,
65 0x7f520e51, 0x8c68059b, 0xabd9831f, 0x19cde05bUL
66};
67
68static const uint32_t iv_sha384[16] = {
69 0x5d9dbbcb, 0xd89e05c1, 0x2a299a62, 0x07d57c36,
70 0x5a015991, 0x17dd7030, 0xd8ec2f15, 0x39590ef7,
71 0x67263367, 0x310bc0ff, 0x874ab48e, 0x11155868,
72 0x0d2e0cdb, 0xa78ff964, 0x1d48b547, 0xa44ffabeUL
73};
74
75static const uint32_t iv_sha512[16] = {
76 0x67e6096a, 0x08c9bcf3, 0x85ae67bb, 0x3ba7ca84,
77 0x72f36e3c, 0x2bf894fe, 0x3af54fa5, 0xf1361d5f,
78 0x7f520e51, 0xd182e6ad, 0x8c68059b, 0x1f6c3e2b,
79 0xabd9831f, 0x6bbd41fb, 0x19cde05b, 0x79217e13UL
80};
81
82static int aspeed_hace_wait_completion(uint32_t reg, uint32_t flag, int timeout_us)
83{
84 uint32_t val;
85
86 return readl_poll_timeout(reg, val, (val & flag) == flag, timeout_us);
87}
88
89static int aspeed_hace_process(struct udevice *dev, void *ctx, const void *ibuf, uint32_t ilen)
90{
91 struct aspeed_hace *hace = dev_get_priv(dev);
92 struct aspeed_hace_ctx *hace_ctx = (struct aspeed_hace_ctx *)ctx;
93 uint32_t sts = readl(hace->base + HACE_STS);
94
95 if (sts & HACE_HASH_BUSY) {
96 debug("HACE engine busy\n");
97 return -EBUSY;
98 }
99
100 writel(HACE_HASH_INT, hace->base + HACE_STS);
101
102 writel((uint32_t)ibuf, hace->base + HACE_HASH_DATA);
103 writel((uint32_t)hace_ctx->digest, hace->base + HACE_HASH_DIGEST);
104 writel((uint32_t)hace_ctx->digest, hace->base + HACE_HASH_HMAC_KEY);
105 writel(ilen, hace->base + HACE_HASH_DATA_LEN);
106 writel(hace_ctx->cmd, hace->base + HACE_HASH_CMD);
107
108 return aspeed_hace_wait_completion(hace->base + HACE_STS,
109 HACE_HASH_INT,
110 1000 + (ilen >> 3));
111}
112
113static int aspeed_hace_init(struct udevice *dev, enum HASH_ALGO algo, void **ctxp)
114{
115 struct aspeed_hace_ctx *hace_ctx;
116
117 hace_ctx = memalign(8, sizeof(struct aspeed_hace_ctx));
118 if (!hace_ctx)
119 return -ENOMEM;
120
121 memset(hace_ctx, 0, sizeof(struct aspeed_hace_ctx));
122
123 hace_ctx->algo = algo;
124 hace_ctx->cmd = HACE_HASH_MODE_ACCUM | HACE_HASH_SHA_BE_EN;
125
126 switch (algo) {
127 case HASH_ALGO_SHA1:
128 hace_ctx->blk_size = 64;
129 hace_ctx->pad_size = 8;
130 hace_ctx->cmd |= HACE_HASH_ALGO_SHA1;
131 memcpy(hace_ctx->digest, iv_sha1, sizeof(iv_sha1));
132 break;
133 case HASH_ALGO_SHA256:
134 hace_ctx->blk_size = 64;
135 hace_ctx->pad_size = 8;
136 hace_ctx->cmd |= HACE_HASH_ALGO_SHA256;
137 memcpy(hace_ctx->digest, iv_sha256, sizeof(iv_sha256));
138 break;
139 case HASH_ALGO_SHA384:
140 hace_ctx->blk_size = 128;
141 hace_ctx->pad_size = 16;
142 hace_ctx->cmd |= HACE_HASH_ALGO_SHA384;
143 memcpy(hace_ctx->digest, iv_sha384, sizeof(iv_sha384));
144 break;
145 case HASH_ALGO_SHA512:
146 hace_ctx->blk_size = 128;
147 hace_ctx->pad_size = 16;
148 hace_ctx->cmd |= HACE_HASH_ALGO_SHA512;
149 memcpy(hace_ctx->digest, iv_sha512, sizeof(iv_sha512));
150 break;
151 default:
152 debug("Unsupported hash algorithm '%s'\n", hash_algo_name(algo));
153 goto free_n_out;
154 };
155
156 *ctxp = hace_ctx;
157
158 return 0;
159
160free_n_out:
161 free(hace_ctx);
162
163 return -EINVAL;
164}
165
166static int aspeed_hace_update(struct udevice *dev, void *ctx, const void *ibuf, uint32_t ilen)
167{
168 int rc;
169 uint32_t left, fill;
170 struct aspeed_hace_ctx *hace_ctx = ctx;
171
172 left = hace_ctx->total[0] & (hace_ctx->blk_size - 1);
173 fill = hace_ctx->blk_size - left;
174
175 hace_ctx->total[0] += ilen;
176 if (hace_ctx->total[0] < ilen)
177 hace_ctx->total[1]++;
178
179 if (left && ilen >= fill) {
180 memcpy(hace_ctx->buf + left, ibuf, fill);
181 rc = aspeed_hace_process(dev, ctx, hace_ctx->buf, hace_ctx->blk_size);
182 if (rc) {
183 debug("failed to process hash, rc=%d\n", rc);
184 return rc;
185 }
186 ilen -= fill;
187 ibuf += fill;
188 left = 0;
189 }
190
191 while (ilen >= hace_ctx->blk_size) {
192 rc = aspeed_hace_process(dev, ctx, ibuf, hace_ctx->blk_size);
193 if (rc) {
194 debug("failed to process hash, rc=%d\n", rc);
195 return rc;
196 }
197
198 ibuf += hace_ctx->blk_size;
199 ilen -= hace_ctx->blk_size;
200 }
201
202 if (ilen)
203 memcpy(hace_ctx->buf + left, ibuf, ilen);
204
205 return 0;
206}
207
208static int aspeed_hace_finish(struct udevice *dev, void *ctx, void *obuf)
209{
210 int rc = 0;
211 uint8_t pad[HASH_BLOCK_BUFSZ * 2];
212 uint32_t last, padn;
213 uint64_t ibits_h, ibits_l;
214 uint64_t ibits_be_h, ibits_be_l;
215 struct aspeed_hace_ctx *hace_ctx = ctx;
216
217 memset(pad, 0, sizeof(pad));
218 pad[0] = 0x80;
219
220 ibits_h = (hace_ctx->total[0] >> 61) | (hace_ctx->total[1] << 3);
221 ibits_be_h = cpu_to_be64(ibits_h);
222
223 ibits_l = (hace_ctx->total[0] << 3);
224 ibits_be_l = cpu_to_be64(ibits_l);
225
226 last = hace_ctx->total[0] & (hace_ctx->blk_size - 1);
227
228 switch (hace_ctx->algo) {
229 case HASH_ALGO_SHA1:
230 case HASH_ALGO_SHA256:
231 padn = (last < 56) ? (56 - last) : (120 - last);
232
233 rc = aspeed_hace_update(dev, ctx, pad, padn);
234 if (rc) {
235 debug("failed to append padding, rc=%d\n", rc);
236 goto free_n_out;
237 }
238
239 rc = aspeed_hace_update(dev, ctx, &ibits_be_l, sizeof(ibits_be_l));
240 if (rc) {
241 debug("failed to append message bits length, rc=%d\n", rc);
242 goto free_n_out;
243 }
244
245 break;
246 case HASH_ALGO_SHA384:
247 case HASH_ALGO_SHA512:
248 padn = (last < 112) ? (112 - last) : (240 - last);
249
250 rc = aspeed_hace_update(dev, ctx, pad, padn);
251 if (rc) {
252 debug("failed to append padding, rc=%d\n", rc);
253 goto free_n_out;
254 }
255
256 rc = aspeed_hace_update(dev, ctx, &ibits_be_h, sizeof(ibits_be_h)) |
257 aspeed_hace_update(dev, ctx, &ibits_be_l, sizeof(ibits_be_l));
258 if (rc) {
259 debug("failed to append message bits length, rc=%d\n", rc);
260 goto free_n_out;
261 }
262
263 break;
264 default:
265 rc = -EINVAL;
266 break;
267 }
268
269 memcpy(obuf, hace_ctx->digest, hash_algo_digest_size(hace_ctx->algo));
270
271free_n_out:
272 free(ctx);
273
274 return rc;
275}
276
277static int aspeed_hace_digest_wd(struct udevice *dev, enum HASH_ALGO algo,
278 const void *ibuf, const uint32_t ilen,
279 void *obuf, uint32_t chunk_sz)
280{
281 int rc;
282 void *ctx;
283 const void *cur, *end;
284 uint32_t chunk;
285
286 rc = aspeed_hace_init(dev, algo, &ctx);
287 if (rc)
288 return rc;
289
Simon Glass83b80872023-02-05 15:40:07 -0700290 if (IS_ENABLED(CONFIG_HW_WATCHDOG) || CONFIG_IS_ENABLED(WATCHDOG)) {
Johnny Huangd91aaa52021-10-27 14:17:27 +0800291 cur = ibuf;
292 end = ibuf + ilen;
293
294 while (cur < end) {
295 chunk = end - cur;
296 if (chunk > chunk_sz)
297 chunk = chunk_sz;
298
299 rc = aspeed_hace_update(dev, ctx, cur, chunk);
300 if (rc)
301 return rc;
302
303 cur += chunk;
Stefan Roese80877fa2022-09-02 14:10:46 +0200304 schedule();
Johnny Huangd91aaa52021-10-27 14:17:27 +0800305 }
306 } else {
307 rc = aspeed_hace_update(dev, ctx, ibuf, ilen);
308 if (rc)
309 return rc;
310 }
311
312 rc = aspeed_hace_finish(dev, ctx, obuf);
313 if (rc)
314 return rc;
315
316 return 0;
317}
318
319static int aspeed_hace_digest(struct udevice *dev, enum HASH_ALGO algo,
320 const void *ibuf, const uint32_t ilen,
321 void *obuf)
322{
323 /* re-use the watchdog version with input length as the chunk_sz */
324 return aspeed_hace_digest_wd(dev, algo, ibuf, ilen, obuf, ilen);
325}
326
327static int aspeed_hace_probe(struct udevice *dev)
328{
329 int rc;
330 struct aspeed_hace *hace = dev_get_priv(dev);
331
332 rc = clk_get_by_index(dev, 0, &hace->clk);
333 if (rc < 0) {
334 debug("cannot get clock for %s: %d\n", dev->name, rc);
335 return rc;
336 }
337
338 rc = clk_enable(&hace->clk);
339 if (rc) {
340 debug("cannot enable clock for %s: %d\n", dev->name, rc);
341 return rc;
342 }
343
344 hace->base = devfdt_get_addr(dev);
345
346 return rc;
347}
348
349static int aspeed_hace_remove(struct udevice *dev)
350{
351 struct aspeed_hace *hace = dev_get_priv(dev);
352
353 clk_disable(&hace->clk);
354
355 return 0;
356}
357
358static const struct hash_ops aspeed_hace_ops = {
359 .hash_init = aspeed_hace_init,
360 .hash_update = aspeed_hace_update,
361 .hash_finish = aspeed_hace_finish,
362 .hash_digest_wd = aspeed_hace_digest_wd,
363 .hash_digest = aspeed_hace_digest,
364};
365
366static const struct udevice_id aspeed_hace_ids[] = {
367 { .compatible = "aspeed,ast2600-hace" },
368 { }
369};
370
371U_BOOT_DRIVER(aspeed_hace) = {
372 .name = "aspeed_hace",
373 .id = UCLASS_HASH,
374 .of_match = aspeed_hace_ids,
375 .ops = &aspeed_hace_ops,
376 .probe = aspeed_hace_probe,
377 .remove = aspeed_hace_remove,
378 .priv_auto = sizeof(struct aspeed_hace),
379 .flags = DM_FLAG_PRE_RELOC,
380};