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