1 /*
2 * (C) Copyright ASPEED Technology Inc.
3 * Copyright 2021 IBM Corp.
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8 #include <common.h>
9 #include <clk.h>
10
11 #include <log.h>
12 #include <asm/io.h>
13 #include <malloc.h>
14 #include <hash.h>
15
16 #include <dm/device.h>
17 #include <dm/fdtaddr.h>
18
19 #include <linux/bitops.h>
20 #include <linux/delay.h>
21 #include <linux/kernel.h>
22 #include <linux/iopoll.h>
23
24 #define ASPEED_HACE_STS 0x1C
25 #define HACE_RSA_ISR BIT(13)
26 #define HACE_CRYPTO_ISR BIT(12)
27 #define HACE_HASH_ISR BIT(9)
28 #define HACE_RSA_BUSY BIT(2)
29 #define HACE_CRYPTO_BUSY BIT(1)
30 #define HACE_HASH_BUSY BIT(0)
31 #define ASPEED_HACE_HASH_SRC 0x20
32 #define ASPEED_HACE_HASH_DIGEST_BUFF 0x24
33 #define ASPEED_HACE_HASH_KEY_BUFF 0x28
34 #define ASPEED_HACE_HASH_DATA_LEN 0x2C
35 #define HACE_SG_LAST BIT(31)
36 #define ASPEED_HACE_HASH_CMD 0x30
37 #define HACE_SHA_BE_EN BIT(3)
38 #define HACE_MD5_LE_EN BIT(2)
39 #define HACE_ALGO_MD5 0
40 #define HACE_ALGO_SHA1 BIT(5)
41 #define HACE_ALGO_SHA224 BIT(6)
42 #define HACE_ALGO_SHA256 (BIT(4) | BIT(6))
43 #define HACE_ALGO_SHA512 (BIT(5) | BIT(6))
44 #define HACE_ALGO_SHA384 (BIT(5) | BIT(6) | BIT(10))
45 #define HACE_SG_EN BIT(18)
46
47 #define ASPEED_MAX_SG 32
48
49 struct aspeed_sg {
50 u32 len;
51 u32 addr;
52 };
53
54 struct aspeed_hash_ctx {
55 u32 method;
56 u32 digest_size;
57 u32 len;
58 u32 count;
59 struct aspeed_sg list[ASPEED_MAX_SG]; /* Must be 8 byte aligned */
60 };
61
62 struct aspeed_hace {
63 struct clk clk;
64 };
65
66 static phys_addr_t base;
67
aspeed_hace_wait_completion(u32 reg,u32 flag,int timeout_us)68 static int aspeed_hace_wait_completion(u32 reg, u32 flag, int timeout_us)
69 {
70 u32 val;
71
72 return readl_poll_timeout(reg, val, (val & flag) == flag, timeout_us);
73 }
74
digest_object(const void * src,unsigned int length,void * digest,u32 method)75 static int digest_object(const void *src, unsigned int length, void *digest,
76 u32 method)
77 {
78 if (!((u32)src & BIT(31))) {
79 debug("HACE src out of bounds: can only copy from SDRAM\n");
80 return -EINVAL;
81 }
82
83 if ((u32)digest & 0x7) {
84 debug("HACE dest alignment incorrect: %p\n", digest);
85 return -EINVAL;
86 }
87
88
89 if (readl(base + ASPEED_HACE_STS) & HACE_HASH_BUSY) {
90 debug("HACE error: engine busy\n");
91 return -EBUSY;
92 }
93
94 /* Clear pending completion status */
95 writel(HACE_HASH_ISR, base + ASPEED_HACE_STS);
96
97 writel((u32)src, base + ASPEED_HACE_HASH_SRC);
98 writel((u32)digest, base + ASPEED_HACE_HASH_DIGEST_BUFF);
99 writel(length, base + ASPEED_HACE_HASH_DATA_LEN);
100 writel(HACE_SHA_BE_EN | method, base + ASPEED_HACE_HASH_CMD);
101
102 /* SHA512 hashing appears to have a througput of about 12MB/s */
103 aspeed_hace_wait_completion(base + ASPEED_HACE_STS, HACE_HASH_ISR,
104 1000 + (length >> 3));
105
106 if (readl(base + ASPEED_HACE_STS)) {
107 debug("\nHACE error 0x%08x, resetting\n", readl(base + 0x1c));
108
109 writel(0x10, 0x1e6e2040);
110 mdelay(5);
111 writel(0x10, 0x1e6e2044);
112 }
113
114 return 0;
115 }
116
hw_sha1(const unsigned char * pbuf,unsigned int buf_len,unsigned char * pout,unsigned int chunk_size)117 void hw_sha1(const unsigned char *pbuf, unsigned int buf_len,
118 unsigned char *pout, unsigned int chunk_size)
119 {
120 int rc;
121
122 rc = digest_object(pbuf, buf_len, pout, HACE_ALGO_SHA1);
123 if (rc)
124 debug("HACE failure: %d\n", rc);
125 }
126
hw_sha256(const unsigned char * pbuf,unsigned int buf_len,unsigned char * pout,unsigned int chunk_size)127 void hw_sha256(const unsigned char *pbuf, unsigned int buf_len,
128 unsigned char *pout, unsigned int chunk_size)
129 {
130 int rc;
131
132 rc = digest_object(pbuf, buf_len, pout, HACE_ALGO_SHA256);
133 if (rc)
134 debug("HACE failure: %d\n", rc);
135 }
136
hw_sha384(const unsigned char * pbuf,unsigned int buf_len,unsigned char * pout,unsigned int chunk_size)137 void hw_sha384(const unsigned char *pbuf, unsigned int buf_len,
138 unsigned char *pout, unsigned int chunk_size)
139 {
140 int rc;
141
142 rc = digest_object(pbuf, buf_len, pout, HACE_ALGO_SHA384);
143 if (rc)
144 debug("HACE failure: %d\n", rc);
145 }
146
hw_sha512(const unsigned char * pbuf,unsigned int buf_len,unsigned char * pout,unsigned int chunk_size)147 void hw_sha512(const unsigned char *pbuf, unsigned int buf_len,
148 unsigned char *pout, unsigned int chunk_size)
149 {
150 int rc;
151
152 rc = digest_object(pbuf, buf_len, pout, HACE_ALGO_SHA512);
153 if (rc)
154 debug("HACE failure: %d\n", rc);
155 }
156
157 #if IS_ENABLED(CONFIG_SHA_PROG_HW_ACCEL)
hw_sha_init(struct hash_algo * algo,void ** ctxp)158 int hw_sha_init(struct hash_algo *algo, void **ctxp)
159 {
160 struct aspeed_hash_ctx *ctx;
161 u32 method;
162
163 if (!strcmp(algo->name, "sha1")) {
164 method = HACE_ALGO_SHA1;
165 }
166 else if (!strcmp(algo->name, "sha256")) {
167 method = HACE_ALGO_SHA256;
168 }
169 else if (!strcmp(algo->name, "sha512")) {
170 method = HACE_ALGO_SHA512;
171 }
172 else {
173 return -ENOTSUPP;
174 }
175
176 ctx = memalign(8, sizeof(*ctx));
177 memset(ctx, '\0', sizeof(*ctx));
178
179 if (ctx == NULL) {
180 debug("HACE error: Cannot allocate memory for context\n");
181 return -ENOMEM;
182 }
183
184 if (((uintptr_t)ctx->list & 0x3) != 0) {
185 printf("HACE error: Invalid alignment for input data\n");
186 return -EINVAL;
187 }
188
189 ctx->method = method | HACE_SG_EN;
190 ctx->digest_size = algo->digest_size;
191 *ctxp = ctx;
192
193 return 0;
194 }
195
hw_sha_update(struct hash_algo * algo,void * hash_ctx,const void * buf,unsigned int size,int is_last)196 int hw_sha_update(struct hash_algo *algo, void *hash_ctx, const void *buf,
197 unsigned int size, int is_last)
198 {
199 struct aspeed_hash_ctx *ctx = hash_ctx;
200 struct aspeed_sg *sg = &ctx->list[ctx->count];
201
202 if (ctx->count >= ARRAY_SIZE(ctx->list)) {
203 debug("HACE error: Reached maximum number of hash segments\n");
204 free(ctx);
205 return -EINVAL;
206 }
207
208 sg->addr = (u32)buf;
209 sg->len = size;
210 if (is_last)
211 sg->len |= HACE_SG_LAST;
212
213 ctx->count++;
214 ctx->len += size;
215
216 return 0;
217 }
218
hw_sha_finish(struct hash_algo * algo,void * hash_ctx,void * dest_buf,int size)219 int hw_sha_finish(struct hash_algo *algo, void *hash_ctx, void *dest_buf, int size)
220 {
221 struct aspeed_hash_ctx *ctx = hash_ctx;
222 int rc;
223
224 if (size < ctx->digest_size) {
225 debug("HACE error: insufficient size on destination buffer\n");
226 free(ctx);
227 return -EINVAL;
228 }
229
230 rc = digest_object(ctx->list, ctx->len, dest_buf, ctx->method);
231 if (rc)
232 debug("HACE Scatter-Gather failure\n");
233
234 free(ctx);
235
236 return rc;
237 }
238 #endif
239
aspeed_hace_probe(struct udevice * dev)240 static int aspeed_hace_probe(struct udevice *dev)
241 {
242 struct aspeed_hace *hace = dev_get_priv(dev);
243 int ret;
244
245 ret = clk_get_by_index(dev, 0, &hace->clk);
246 if (ret < 0) {
247 debug("Can't get clock for %s: %d\n", dev->name, ret);
248 return ret;
249 }
250
251 ret = clk_enable(&hace->clk);
252 if (ret) {
253 debug("Failed to enable fsi clock (%d)\n", ret);
254 return ret;
255 }
256
257 /* As the crypto code does not pass us any driver state */
258 base = devfdt_get_addr(dev);
259
260 return ret;
261 }
262
aspeed_hace_remove(struct udevice * dev)263 static int aspeed_hace_remove(struct udevice *dev)
264 {
265 struct aspeed_hace *hace = dev_get_priv(dev);
266
267 clk_disable(&hace->clk);
268
269 return 0;
270 }
271
272 static const struct udevice_id aspeed_hace_ids[] = {
273 { .compatible = "aspeed,ast2600-hace" },
274 { }
275 };
276
277 U_BOOT_DRIVER(aspeed_hace) = {
278 .name = "aspeed_hace",
279 .id = UCLASS_MISC,
280 .of_match = aspeed_hace_ids,
281 .probe = aspeed_hace_probe,
282 .remove = aspeed_hace_remove,
283 .priv_auto_alloc_size = sizeof(struct aspeed_hace),
284 .flags = DM_FLAG_PRE_RELOC,
285 };
286