xref: /rk3399_rockchip-uboot/drivers/crypto/rockchip/crypto_v1.c (revision f9ebf7a1deba3da5e8597b6f9a84d0201ee8f0e7)
1a3d00835SJoseph Chen // SPDX-License-Identifier: GPL-2.0
2a3d00835SJoseph Chen /*
3a3d00835SJoseph Chen  * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
4a3d00835SJoseph Chen  */
5a3d00835SJoseph Chen 
6a3d00835SJoseph Chen #include <common.h>
7a3d00835SJoseph Chen #include <clk.h>
8a3d00835SJoseph Chen #include <crypto.h>
9a3d00835SJoseph Chen #include <dm.h>
10a3d00835SJoseph Chen #include <rockchip/crypto_v1.h>
11a3d00835SJoseph Chen #include <asm/io.h>
12a3d00835SJoseph Chen #include <asm/arch/hardware.h>
13a3d00835SJoseph Chen #include <asm/arch/clock.h>
14a3d00835SJoseph Chen 
15a3d00835SJoseph Chen #define CRYPTO_V1_DEFAULT_RATE		100000000
16a3d00835SJoseph Chen 
17a3d00835SJoseph Chen struct rockchip_crypto_priv {
18a3d00835SJoseph Chen 	struct rk_crypto_reg *reg;
19a3d00835SJoseph Chen 	struct clk clk;
20a3d00835SJoseph Chen 	u32 frequency;
21a3d00835SJoseph Chen 	char *clocks;
22a3d00835SJoseph Chen 	u32 nclocks;
23a3d00835SJoseph Chen 	u32 length;
24a3d00835SJoseph Chen };
25a3d00835SJoseph Chen 
26a3d00835SJoseph Chen static u32 rockchip_crypto_capability(struct udevice *dev)
27a3d00835SJoseph Chen {
28a3d00835SJoseph Chen 	return CRYPTO_MD5 |
29a3d00835SJoseph Chen 	       CRYPTO_SHA1 |
30a3d00835SJoseph Chen 	       CRYPTO_SHA256 |
31a3d00835SJoseph Chen 	       CRYPTO_RSA512 |
32a3d00835SJoseph Chen 	       CRYPTO_RSA1024 |
33a3d00835SJoseph Chen 	       CRYPTO_RSA2048;
34a3d00835SJoseph Chen }
35a3d00835SJoseph Chen 
36a3d00835SJoseph Chen static int rockchip_crypto_sha_init(struct udevice *dev, sha_context *ctx)
37a3d00835SJoseph Chen {
38a3d00835SJoseph Chen 	struct rockchip_crypto_priv *priv = dev_get_priv(dev);
39a3d00835SJoseph Chen 	struct rk_crypto_reg *reg = priv->reg;
40a3d00835SJoseph Chen 	u32 val;
41a3d00835SJoseph Chen 
42*f9ebf7a1SJoseph Chen 	if (!ctx)
43a3d00835SJoseph Chen 		return -EINVAL;
44a3d00835SJoseph Chen 
45*f9ebf7a1SJoseph Chen 	if (!ctx->length) {
46*f9ebf7a1SJoseph Chen 		printf("%s: Err: crypto v1 request total data "
47*f9ebf7a1SJoseph Chen 		       "length when sha init\n", __func__);
48*f9ebf7a1SJoseph Chen 		return -EINVAL;
49*f9ebf7a1SJoseph Chen 	}
50*f9ebf7a1SJoseph Chen 
51a3d00835SJoseph Chen 	priv->length = 0;
52a3d00835SJoseph Chen 	writel(ctx->length, &reg->crypto_hash_msg_len);
53a3d00835SJoseph Chen 	if (ctx->algo == CRYPTO_SHA256) {
54a3d00835SJoseph Chen 		/* Set SHA256 mode and out byte swap */
55a3d00835SJoseph Chen 		writel(HASH_SWAP_DO | ENGINE_SELECTION_SHA256,
56a3d00835SJoseph Chen 		       &reg->crypto_hash_ctrl);
57a3d00835SJoseph Chen 
58a3d00835SJoseph Chen 		val = readl(&reg->crypto_conf);
59a3d00835SJoseph Chen 		val &= ~BYTESWAP_HRFIFO;
60a3d00835SJoseph Chen 		writel(val, &reg->crypto_conf);
61a3d00835SJoseph Chen 	} else if (ctx->algo == CRYPTO_SHA1) {
62a3d00835SJoseph Chen 		/* Set SHA160 input byte swap */
63a3d00835SJoseph Chen 		val = readl(&reg->crypto_conf);
64a3d00835SJoseph Chen 		val |= BYTESWAP_HRFIFO;
65a3d00835SJoseph Chen 		writel(val, &reg->crypto_conf);
66a3d00835SJoseph Chen 
67a3d00835SJoseph Chen 		/* Set SHA160 mode and out byte swap */
68a3d00835SJoseph Chen 		writel(HASH_SWAP_DO, &reg->crypto_hash_ctrl);
69a3d00835SJoseph Chen 	} else if (ctx->algo == CRYPTO_MD5) {
70a3d00835SJoseph Chen 		/* Set MD5 input byte swap */
71a3d00835SJoseph Chen 		val = readl(&reg->crypto_conf);
72a3d00835SJoseph Chen 		val |= BYTESWAP_HRFIFO;
73a3d00835SJoseph Chen 		writel(val, &reg->crypto_conf);
74a3d00835SJoseph Chen 
75a3d00835SJoseph Chen 		/* Set MD5 mode and out byte swap */
76a3d00835SJoseph Chen 		writel(HASH_SWAP_DO | ENGINE_SELECTION_MD5,
77a3d00835SJoseph Chen 		       &reg->crypto_hash_ctrl);
78a3d00835SJoseph Chen 	} else {
79a3d00835SJoseph Chen 		return -EINVAL;
80a3d00835SJoseph Chen 	}
81a3d00835SJoseph Chen 
82a3d00835SJoseph Chen 	rk_setreg(&reg->crypto_ctrl, HASH_FLUSH);
83a3d00835SJoseph Chen 	do {} while (readl(&reg->crypto_ctrl) & HASH_FLUSH);
84a3d00835SJoseph Chen 
85a3d00835SJoseph Chen 	/* SHA256 needs input byte swap */
86a3d00835SJoseph Chen 	if (ctx->algo == CRYPTO_SHA256) {
87a3d00835SJoseph Chen 		val = readl(&reg->crypto_conf);
88a3d00835SJoseph Chen 		val |= BYTESWAP_HRFIFO;
89a3d00835SJoseph Chen 		writel(val, &reg->crypto_conf);
90a3d00835SJoseph Chen 	}
91a3d00835SJoseph Chen 
92a3d00835SJoseph Chen 	return 0;
93a3d00835SJoseph Chen }
94a3d00835SJoseph Chen 
95a3d00835SJoseph Chen static int rockchip_crypto_sha_update(struct udevice *dev,
96a3d00835SJoseph Chen 				      u32 *input, u32 len)
97a3d00835SJoseph Chen {
98a3d00835SJoseph Chen 	struct rockchip_crypto_priv *priv = dev_get_priv(dev);
99a3d00835SJoseph Chen 	struct rk_crypto_reg *reg = priv->reg;
100a3d00835SJoseph Chen 
101a3d00835SJoseph Chen 	if (!len)
102a3d00835SJoseph Chen 		return -EINVAL;
103a3d00835SJoseph Chen 
104a3d00835SJoseph Chen 	priv->length += len;
105a3d00835SJoseph Chen 
106a3d00835SJoseph Chen 	/* Must flush dcache before crypto DMA fetch data region */
107a3d00835SJoseph Chen 	flush_cache((unsigned long)input, len);
108a3d00835SJoseph Chen 
109a3d00835SJoseph Chen 	/* Wait last complete */
110a3d00835SJoseph Chen 	do {} while (readl(&reg->crypto_ctrl) & HASH_START);
111a3d00835SJoseph Chen 
112a3d00835SJoseph Chen 	/* Hash Done Interrupt */
113a3d00835SJoseph Chen 	writel(HASH_DONE_INT, &reg->crypto_intsts);
114a3d00835SJoseph Chen 
115a3d00835SJoseph Chen 	/* Set data base and length */
116a3d00835SJoseph Chen 	writel((u32)(ulong)input, &reg->crypto_hrdmas);
117a3d00835SJoseph Chen 	writel((len + 3) >> 2, &reg->crypto_hrdmal);
118a3d00835SJoseph Chen 
119a3d00835SJoseph Chen 	/* Write 1 to start. When finishes, the core will clear it */
120a3d00835SJoseph Chen 	rk_setreg(&reg->crypto_ctrl, HASH_START);
121a3d00835SJoseph Chen 
122a3d00835SJoseph Chen 	return 0;
123a3d00835SJoseph Chen }
124a3d00835SJoseph Chen 
125a3d00835SJoseph Chen static int rockchip_crypto_sha_final(struct udevice *dev,
126a3d00835SJoseph Chen 				     sha_context *ctx, u8 *output)
127a3d00835SJoseph Chen {
128a3d00835SJoseph Chen 	struct rockchip_crypto_priv *priv = dev_get_priv(dev);
129a3d00835SJoseph Chen 	struct rk_crypto_reg *reg = priv->reg;
130a3d00835SJoseph Chen 	u32 *buf = (u32 *)output;
131a3d00835SJoseph Chen 	u32 nbits;
132a3d00835SJoseph Chen 	int i;
133a3d00835SJoseph Chen 
134a3d00835SJoseph Chen 	if (priv->length != ctx->length) {
135a3d00835SJoseph Chen 		printf("%s: Err: update total length(0x%x) is not equal "
136a3d00835SJoseph Chen 		       "to init total length(0x%x)!\n",
137a3d00835SJoseph Chen 		       __func__, priv->length, ctx->length);
138a3d00835SJoseph Chen 		return -EIO;
139a3d00835SJoseph Chen 	}
140a3d00835SJoseph Chen 
141a3d00835SJoseph Chen 	/* Wait last complete */
142a3d00835SJoseph Chen 	do {} while (readl(&reg->crypto_ctrl) & HASH_START);
143a3d00835SJoseph Chen 
144a3d00835SJoseph Chen 	/* It is high when finish, and it will not be low until it restart */
145a3d00835SJoseph Chen 	do {} while (!readl(&reg->crypto_hash_sts));
146a3d00835SJoseph Chen 
147a3d00835SJoseph Chen 	/* Read hash data, per-data 32-bit */
148a3d00835SJoseph Chen 	nbits = crypto_algo_nbits(ctx->algo);
149*f9ebf7a1SJoseph Chen 	for (i = 0; i < BITS2WORD(nbits); i++)
150a3d00835SJoseph Chen 		buf[i] = readl(&reg->crypto_hash_dout[i]);
151a3d00835SJoseph Chen 
152a3d00835SJoseph Chen 	return 0;
153a3d00835SJoseph Chen }
154a3d00835SJoseph Chen 
155a3d00835SJoseph Chen static int rockchip_crypto_rsa_verify(struct udevice *dev, rsa_key *ctx,
156a3d00835SJoseph Chen 				      u8 *sign, u8 *output)
157a3d00835SJoseph Chen {
158a3d00835SJoseph Chen 	struct rockchip_crypto_priv *priv = dev_get_priv(dev);
159a3d00835SJoseph Chen 	struct rk_crypto_reg *reg = priv->reg;
160a3d00835SJoseph Chen 	u32 nbits, *buf = (u32 *)output;
161a3d00835SJoseph Chen 	int i, value;
162a3d00835SJoseph Chen 
163a3d00835SJoseph Chen 	if (!ctx)
164a3d00835SJoseph Chen 		return -EINVAL;
165a3d00835SJoseph Chen 
166a3d00835SJoseph Chen 	if (ctx->algo == CRYPTO_RSA512)
167a3d00835SJoseph Chen 		value = PKA_BLOCK_SIZE_512;
168a3d00835SJoseph Chen 	else if (ctx->algo == CRYPTO_RSA1024)
169a3d00835SJoseph Chen 		value = PKA_BLOCK_SIZE_1024;
170a3d00835SJoseph Chen 	else if (ctx->algo == CRYPTO_RSA2048)
171a3d00835SJoseph Chen 		value = PKA_BLOCK_SIZE_2048;
172a3d00835SJoseph Chen 	else
173a3d00835SJoseph Chen 		return -EINVAL;
174a3d00835SJoseph Chen 
175a3d00835SJoseph Chen 	/* Specify the nbits of N in PKA calculation */
176a3d00835SJoseph Chen 	writel(value, &reg->crypto_pka_ctrl);
177a3d00835SJoseph Chen 
178a3d00835SJoseph Chen 	/* Flush SHA and RSA */
179a3d00835SJoseph Chen 	rk_setreg(&reg->crypto_ctrl, PKA_HASH_CTRL);
180a3d00835SJoseph Chen 	writel(0xffffffff, &reg->crypto_intsts);
181a3d00835SJoseph Chen 	do {} while (readl(&reg->crypto_ctrl) & PKA_CTRL);
182a3d00835SJoseph Chen 
183a3d00835SJoseph Chen 	/* Clean PKA done interrupt */
184a3d00835SJoseph Chen 	writel(PKA_DONE_INT, &reg->crypto_intsts);
185a3d00835SJoseph Chen 
186a3d00835SJoseph Chen 	/* Set m/n/e/c */
187a3d00835SJoseph Chen 	nbits = crypto_algo_nbits(ctx->algo);
188a3d00835SJoseph Chen 	memcpy((void *)&reg->crypto_pka_m, (void *)sign,   BITS2BYTE(nbits));
189a3d00835SJoseph Chen 	memcpy((void *)&reg->crypto_pka_n, (void *)ctx->n, BITS2BYTE(nbits));
190a3d00835SJoseph Chen 	memcpy((void *)&reg->crypto_pka_e, (void *)ctx->e, BITS2BYTE(nbits));
191a3d00835SJoseph Chen 	memcpy((void *)&reg->crypto_pka_c, (void *)ctx->c, BITS2BYTE(nbits));
192a3d00835SJoseph Chen 	do {} while (readl(&reg->crypto_ctrl) & PKA_START);
193a3d00835SJoseph Chen 
194a3d00835SJoseph Chen 	/* Start PKA */
195a3d00835SJoseph Chen 	rk_setreg(&reg->crypto_ctrl, PKA_START);
196a3d00835SJoseph Chen 
197a3d00835SJoseph Chen 	/* Wait PKA done */
198a3d00835SJoseph Chen 	do {} while (readl(&reg->crypto_ctrl) & PKA_START);
199a3d00835SJoseph Chen 
200a3d00835SJoseph Chen 	/* Read hash data, per-data 32-bit */
201a3d00835SJoseph Chen 	for (i = 0; i < BITS2WORD(nbits); i++)
202a3d00835SJoseph Chen 		buf[i] = readl(&reg->crypto_pka_m[i]);
203a3d00835SJoseph Chen 
204a3d00835SJoseph Chen 	return 0;
205a3d00835SJoseph Chen }
206a3d00835SJoseph Chen 
207a3d00835SJoseph Chen static const struct dm_crypto_ops rockchip_crypto_ops = {
208a3d00835SJoseph Chen 	.capability = rockchip_crypto_capability,
209a3d00835SJoseph Chen 	.sha_init   = rockchip_crypto_sha_init,
210a3d00835SJoseph Chen 	.sha_update = rockchip_crypto_sha_update,
211a3d00835SJoseph Chen 	.sha_final  = rockchip_crypto_sha_final,
212a3d00835SJoseph Chen 	.rsa_verify = rockchip_crypto_rsa_verify,
213a3d00835SJoseph Chen };
214a3d00835SJoseph Chen 
215a3d00835SJoseph Chen /*
216a3d00835SJoseph Chen  * Only use "clocks" to parse crypto clock id and use rockchip_get_clk().
217a3d00835SJoseph Chen  * Because we always add crypto node in U-Boot dts, when kernel dtb enabled :
218a3d00835SJoseph Chen  *
219a3d00835SJoseph Chen  *   1. There is cru phandle mismatch between U-Boot and kernel dtb;
220a3d00835SJoseph Chen  *   2. CONFIG_OF_SPL_REMOVE_PROPS removes clock property;
221a3d00835SJoseph Chen  */
222a3d00835SJoseph Chen static int rockchip_crypto_ofdata_to_platdata(struct udevice *dev)
223a3d00835SJoseph Chen {
224a3d00835SJoseph Chen 	struct rockchip_crypto_priv *priv = dev_get_priv(dev);
225a3d00835SJoseph Chen 	int len;
226a3d00835SJoseph Chen 
227a3d00835SJoseph Chen 	if (!dev_read_prop(dev, "clocks", &len)) {
228a3d00835SJoseph Chen 		printf("Can't find \"clocks\" property\n");
229a3d00835SJoseph Chen 		return -EINVAL;
230a3d00835SJoseph Chen 	}
231a3d00835SJoseph Chen 
232a3d00835SJoseph Chen 	priv->clocks = malloc(len);
233a3d00835SJoseph Chen 	if (!priv->clocks)
234a3d00835SJoseph Chen 		return -ENOMEM;
235a3d00835SJoseph Chen 
236a3d00835SJoseph Chen 	priv->nclocks = len / sizeof(u32);
237a3d00835SJoseph Chen 	if (dev_read_u32_array(dev, "clocks", (u32 *)priv->clocks,
238a3d00835SJoseph Chen 			       priv->nclocks)) {
239a3d00835SJoseph Chen 		printf("Can't read \"clocks\" property\n");
240a3d00835SJoseph Chen 		return -EINVAL;
241a3d00835SJoseph Chen 	}
242a3d00835SJoseph Chen 
243a3d00835SJoseph Chen 	priv->reg = dev_read_addr_ptr(dev);
244a3d00835SJoseph Chen 	priv->frequency = dev_read_u32_default(dev, "clock-frequency",
245a3d00835SJoseph Chen 					       CRYPTO_V1_DEFAULT_RATE);
246a3d00835SJoseph Chen 
247a3d00835SJoseph Chen 	return 0;
248a3d00835SJoseph Chen }
249a3d00835SJoseph Chen 
250a3d00835SJoseph Chen static int rockchip_crypto_probe(struct udevice *dev)
251a3d00835SJoseph Chen {
252a3d00835SJoseph Chen 	struct rockchip_crypto_priv *priv = dev_get_priv(dev);
253a3d00835SJoseph Chen 	u32 *clocks;
254a3d00835SJoseph Chen 	int i, ret;
255a3d00835SJoseph Chen 
256a3d00835SJoseph Chen 	ret = rockchip_get_clk(&priv->clk.dev);
257a3d00835SJoseph Chen 	if (ret) {
258a3d00835SJoseph Chen 		printf("Failed to get clk device, ret=%d\n", ret);
259a3d00835SJoseph Chen 		return ret;
260a3d00835SJoseph Chen 	}
261a3d00835SJoseph Chen 
262a3d00835SJoseph Chen 	clocks = (u32 *)priv->clocks;
263a3d00835SJoseph Chen 	for (i = 1; i < priv->nclocks; i += 2) {
264a3d00835SJoseph Chen 		priv->clk.id = clocks[i];
265a3d00835SJoseph Chen 		ret = clk_set_rate(&priv->clk, priv->frequency);
266a3d00835SJoseph Chen 		if (ret < 0) {
267a3d00835SJoseph Chen 			printf("%s: Failed to set clk(%ld): ret=%d\n",
268a3d00835SJoseph Chen 			       __func__, priv->clk.id, ret);
269a3d00835SJoseph Chen 			return ret;
270a3d00835SJoseph Chen 		}
271a3d00835SJoseph Chen 	}
272a3d00835SJoseph Chen 
273a3d00835SJoseph Chen 	return 0;
274a3d00835SJoseph Chen }
275a3d00835SJoseph Chen 
276a3d00835SJoseph Chen static const struct udevice_id rockchip_crypto_ids[] = {
277a3d00835SJoseph Chen 	{ .compatible = "rockchip,rk3399-crypto" },
278a3d00835SJoseph Chen 	{ .compatible = "rockchip,rk3368-crypto" },
279a3d00835SJoseph Chen 	{ .compatible = "rockchip,rk3328-crypto" },
280a3d00835SJoseph Chen 	{ .compatible = "rockchip,rk3288-crypto" },
281a3d00835SJoseph Chen 	{ .compatible = "rockchip,rk322x-crypto" },
282a3d00835SJoseph Chen 	{ .compatible = "rockchip,rk312x-crypto" },
283a3d00835SJoseph Chen 	{ }
284a3d00835SJoseph Chen };
285a3d00835SJoseph Chen 
286a3d00835SJoseph Chen U_BOOT_DRIVER(rockchip_crypto_v1) = {
287a3d00835SJoseph Chen 	.name		= "rockchip_crypto_v1",
288a3d00835SJoseph Chen 	.id		= UCLASS_CRYPTO,
289a3d00835SJoseph Chen 	.of_match	= rockchip_crypto_ids,
290a3d00835SJoseph Chen 	.ops		= &rockchip_crypto_ops,
291a3d00835SJoseph Chen 	.probe		= rockchip_crypto_probe,
292a3d00835SJoseph Chen 	.ofdata_to_platdata = rockchip_crypto_ofdata_to_platdata,
293a3d00835SJoseph Chen 	.priv_auto_alloc_size = sizeof(struct rockchip_crypto_priv),
294a3d00835SJoseph Chen };
295