blob: 26b97bdd92bb65a9245a4634625b12e45f387f0f [file] [log] [blame]
Chia-Wei Wang3827c332024-08-30 15:23:34 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright 2024 ASPEED Technology Inc.
4 */
5#include <asm/io.h>
6#include <config.h>
7#include <dm.h>
8#include <linux/bitfield.h>
9#include <linux/bitops.h>
10#include <linux/iopoll.h>
11#include <malloc.h>
12#include <u-boot/hash.h>
13#include <watchdog.h>
14
15/* SHA register offsets */
16#define CPTRA_SHA_LOCK 0x00
17#define CPTRA_SHA_USER 0x04
18#define CPTRA_SHA_MODE 0x08
19#define CPTRA_SHA_MODE_ENDIAN BIT(2)
20#define CPTRA_SHA_MODE_SEL GENMASK(1, 0)
21#define CPTRA_SHA_DLEN 0x10
22#define CPTRA_SHA_DATAIN 0x14
23#define CPTRA_SHA_EXEC 0x18
24#define CPTRA_SHA_STS 0x1c
25#define CPTRA_SHA_STS_SOC_LOCK BIT(1)
26#define CPTRA_SHA_STS_VLD BIT(0)
27#define CPTRA_SHA_DIGEST(n) (0x20 + ((n) << 2))
28#define CPTRA_SHA_CTRL 0x60
29#define CPTRA_SHA_CTRL_ZEROIZE BIT(0)
30
31enum cptra_sha_modes {
32 CPTRA_SHA384_STREAM,
33 CPTRA_SHA512_STREAM,
34};
35
36struct cptra_sha_ctx {
37 enum HASH_ALGO algo;
38 uint32_t dgst_len;
39};
40
41struct cptra_sha {
42 void *regs;
43};
44
45static int cptra_sha_init(struct udevice *dev, enum HASH_ALGO algo, void **ctxp)
46{
47 struct cptra_sha_ctx *cs_ctx;
48 struct cptra_sha *cs;
49 uint32_t mode;
50 uint32_t reg;
51 int rc;
52
53 cs_ctx = malloc(sizeof(struct cptra_sha_ctx));
54 if (!cs_ctx)
55 return -ENOMEM;
56
57 memset(cs_ctx, 0, sizeof(struct cptra_sha_ctx));
58
59 cs_ctx->algo = algo;
60
61 switch (algo) {
62 case HASH_ALGO_SHA384:
63 mode = CPTRA_SHA384_STREAM;
64 cs_ctx->dgst_len = 48;
65 break;
66 case HASH_ALGO_SHA512:
67 mode = CPTRA_SHA512_STREAM;
68 cs_ctx->dgst_len = 64;
69 break;
70 default:
71 rc = -EINVAL;
72 goto free_n_out;
73 };
74
75 cs = dev_get_priv(dev);
76
77 /* get CPTRA SHA lock */
78 if (readl_poll_timeout(cs->regs + CPTRA_SHA_LOCK, reg, reg == 0, 1000000))
79 return -EBUSY;
80
81 /* zero clear SHA */
82 writel(CPTRA_SHA_CTRL_ZEROIZE, cs->regs + CPTRA_SHA_CTRL);
83
84 /* zero clear length */
85 writel(0x0, cs->regs + CPTRA_SHA_DLEN);
86
87 /* set SHA mode */
88 reg = readl(cs->regs + CPTRA_SHA_MODE);
89 reg &= ~(CPTRA_SHA_MODE_SEL);
90 reg |= FIELD_PREP(CPTRA_SHA_MODE_SEL, mode);
91 writel(reg, cs->regs + CPTRA_SHA_MODE);
92
93 *ctxp = cs_ctx;
94
95 return 0;
96
97free_n_out:
98 free(cs_ctx);
99
100 return rc;
101}
102
103static int cptra_sha_update(struct udevice *dev, void *ctx, const void *ibuf, uint32_t ilen)
104{
105 struct cptra_sha *cs;
106 uint32_t din_be;
107 uint32_t dlen_sum;
108 uint8_t *p8;
109 uint32_t i;
110
111 cs = dev_get_priv(dev);
112
113 /* update length */
114 dlen_sum = readl(cs->regs + CPTRA_SHA_DLEN) + ilen;
115 writel(dlen_sum, cs->regs + CPTRA_SHA_DLEN);
116
117 din_be = 0;
118 for (i = 0, p8 = (uint8_t *)ibuf; i < ilen; ++i) {
119 if (i && (i % sizeof(din_be) == 0)) {
120 writel(din_be, cs->regs + CPTRA_SHA_DATAIN);
121 din_be = 0;
122 }
123
124 din_be <<= 8;
125 din_be |= p8[i];
126 }
127
128 if (i % sizeof(din_be))
129 din_be <<= (8 * (sizeof(din_be) - (i % sizeof(din_be))));
130
131 writel(din_be, cs->regs + CPTRA_SHA_DATAIN);
132
133 return 0;
134}
135
136static int cptra_sha_finish(struct udevice *dev, void *ctx, void *obuf)
137{
138 struct cptra_sha_ctx *cs_ctx;
139 struct cptra_sha *cs;
140 uint32_t i, *p32;
141 uint32_t sts;
142
143 cs = dev_get_priv(dev);
144 cs_ctx = (struct cptra_sha_ctx *)ctx;
145
146 /* trigger SHA calculation */
147 writel(0x1, cs->regs + CPTRA_SHA_EXEC);
148
149 /* wait for completion */
150 while (1) {
151 sts = readl(cs->regs + CPTRA_SHA_STS);
152 if (sts & CPTRA_SHA_STS_VLD)
153 break;
154 }
155
156 /* get the SHA digest in big-endian */
157 p32 = (uint32_t *)obuf;
158 for (i = 0; i < (cs_ctx->dgst_len / sizeof(*p32)); ++i, p32++)
159 *p32 = be32_to_cpu(readl(cs->regs + CPTRA_SHA_DIGEST(i)));
160
161 /* release CPTRA SHA lock */
162 writel(0x1, cs->regs + CPTRA_SHA_LOCK);
163
164 free(cs_ctx);
165
166 return 0;
167}
168
169static int cptra_sha_digest_wd(struct udevice *dev, enum HASH_ALGO algo,
170 const void *ibuf, const uint32_t ilen,
171 void *obuf, uint32_t chunk_sz)
172{
173 const void *cur, *end;
174 uint32_t chunk;
175 void *ctx;
176 int rc;
177
178 rc = cptra_sha_init(dev, algo, &ctx);
179 if (rc)
180 return rc;
181
182 if (IS_ENABLED(CONFIG_HW_WATCHDOG) || CONFIG_IS_ENABLED(WATCHDOG)) {
183 cur = ibuf;
184 end = ibuf + ilen;
185
186 while (cur < end) {
187 chunk = end - cur;
188 if (chunk > chunk_sz)
189 chunk = chunk_sz;
190
191 rc = cptra_sha_update(dev, ctx, cur, chunk);
192 if (rc)
193 return rc;
194
195 cur += chunk;
196 schedule();
197 }
198 } else {
199 rc = cptra_sha_update(dev, ctx, ibuf, ilen);
200 if (rc)
201 return rc;
202 }
203
204 rc = cptra_sha_finish(dev, ctx, obuf);
205 if (rc)
206 return rc;
207
208 return 0;
209}
210
211static int cptra_sha_digest(struct udevice *dev, enum HASH_ALGO algo,
212 const void *ibuf, const uint32_t ilen, void *obuf)
213{
214 /* re-use the watchdog version with input length as the chunk_sz */
215 return cptra_sha_digest_wd(dev, algo, ibuf, ilen, obuf, ilen);
216}
217
218static int cptra_sha_probe(struct udevice *dev)
219{
220 struct cptra_sha *cs = dev_get_priv(dev);
221
222 cs->regs = (void *)devfdt_get_addr(dev);
223 if (cs->regs == (void *)FDT_ADDR_T_NONE) {
224 debug("cannot map Caliptra SHA ACC registers\n");
225 return -ENODEV;
226 }
227
228 return 0;
229}
230
231static int cptra_sha_remove(struct udevice *dev)
232{
233 return 0;
234}
235
236static const struct hash_ops cptra_sha_ops = {
237 .hash_init = cptra_sha_init,
238 .hash_update = cptra_sha_update,
239 .hash_finish = cptra_sha_finish,
240 .hash_digest_wd = cptra_sha_digest_wd,
241 .hash_digest = cptra_sha_digest,
242};
243
244static const struct udevice_id cptra_sha_ids[] = {
245 { .compatible = "aspeed,ast2700-cptra-sha" },
246 { }
247};
248
249U_BOOT_DRIVER(aspeed_cptra_sha) = {
250 .name = "aspeed_cptra_sha",
251 .id = UCLASS_HASH,
252 .of_match = cptra_sha_ids,
253 .ops = &cptra_sha_ops,
254 .probe = cptra_sha_probe,
255 .remove = cptra_sha_remove,
256 .priv_auto = sizeof(struct cptra_sha),
257 .flags = DM_FLAG_PRE_RELOC,
258};