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