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