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