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