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