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