xref: /rk3399_rockchip-uboot/drivers/crypto/rockchip/crypto_v1.c (revision 73b4df6a98d2d973cbf1e2b18947abbdbdb82bc1)
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 static int rockchip_crypto_rsa_verify(struct udevice *dev, rsa_key *ctx,
166 				      u8 *sign, u8 *output)
167 {
168 	struct rockchip_crypto_priv *priv = dev_get_priv(dev);
169 	struct rk_crypto_reg *reg = priv->reg;
170 	u32 nbits, *buf = (u32 *)output;
171 	int i, value;
172 
173 	if (!ctx)
174 		return -EINVAL;
175 
176 	if (ctx->algo == CRYPTO_RSA512)
177 		value = PKA_BLOCK_SIZE_512;
178 	else if (ctx->algo == CRYPTO_RSA1024)
179 		value = PKA_BLOCK_SIZE_1024;
180 	else if (ctx->algo == CRYPTO_RSA2048)
181 		value = PKA_BLOCK_SIZE_2048;
182 	else
183 		return -EINVAL;
184 
185 	/* Specify the nbits of N in PKA calculation */
186 	writel(value, &reg->crypto_pka_ctrl);
187 
188 	/* Flush SHA and RSA */
189 	rk_setreg(&reg->crypto_ctrl, PKA_HASH_CTRL);
190 	writel(0xffffffff, &reg->crypto_intsts);
191 	do {} while (readl(&reg->crypto_ctrl) & PKA_CTRL);
192 
193 	/* Clean PKA done interrupt */
194 	writel(PKA_DONE_INT, &reg->crypto_intsts);
195 
196 	/* Set m/n/e/c */
197 	nbits = crypto_algo_nbits(ctx->algo);
198 	memcpy((void *)&reg->crypto_pka_m, (void *)sign,   BITS2BYTE(nbits));
199 	memcpy((void *)&reg->crypto_pka_n, (void *)ctx->n, BITS2BYTE(nbits));
200 	memcpy((void *)&reg->crypto_pka_e, (void *)ctx->e, BITS2BYTE(nbits));
201 	memcpy((void *)&reg->crypto_pka_c, (void *)ctx->c, BITS2BYTE(nbits));
202 	do {} while (readl(&reg->crypto_ctrl) & PKA_START);
203 
204 	/* Start PKA */
205 	rk_setreg(&reg->crypto_ctrl, PKA_START);
206 
207 	/* Wait PKA done */
208 	do {} while (readl(&reg->crypto_ctrl) & PKA_START);
209 
210 	/* Read hash data, per-data 32-bit */
211 	for (i = 0; i < BITS2WORD(nbits); i++)
212 		buf[i] = readl(&reg->crypto_pka_m[i]);
213 
214 	return 0;
215 }
216 
217 static const struct dm_crypto_ops rockchip_crypto_ops = {
218 	.capability = rockchip_crypto_capability,
219 	.sha_init   = rockchip_crypto_sha_init,
220 	.sha_update = rockchip_crypto_sha_update,
221 	.sha_final  = rockchip_crypto_sha_final,
222 	.rsa_verify = rockchip_crypto_rsa_verify,
223 };
224 
225 /*
226  * Only use "clocks" to parse crypto clock id and use rockchip_get_clk().
227  * Because we always add crypto node in U-Boot dts, when kernel dtb enabled :
228  *
229  *   1. There is cru phandle mismatch between U-Boot and kernel dtb;
230  *   2. CONFIG_OF_SPL_REMOVE_PROPS removes clock property;
231  */
232 static int rockchip_crypto_ofdata_to_platdata(struct udevice *dev)
233 {
234 	struct rockchip_crypto_priv *priv = dev_get_priv(dev);
235 	int len;
236 
237 	if (!dev_read_prop(dev, "clocks", &len)) {
238 		printf("Crypto-v1: can't find \"clocks\" property\n");
239 		return -EINVAL;
240 	}
241 
242 	priv->clocks = malloc(len);
243 	if (!priv->clocks)
244 		return -ENOMEM;
245 
246 	priv->nclocks = len / sizeof(u32);
247 	if (dev_read_u32_array(dev, "clocks", (u32 *)priv->clocks,
248 			       priv->nclocks)) {
249 		printf("Crypto-v1: can't read \"clocks\" property\n");
250 		return -EINVAL;
251 	}
252 
253 	priv->reg = dev_read_addr_ptr(dev);
254 	priv->frequency = dev_read_u32_default(dev, "clock-frequency",
255 					       CRYPTO_V1_DEFAULT_RATE);
256 
257 	return 0;
258 }
259 
260 static int rockchip_crypto_probe(struct udevice *dev)
261 {
262 	struct rockchip_crypto_priv *priv = dev_get_priv(dev);
263 	u32 *clocks;
264 	int i, ret;
265 
266 	ret = rockchip_get_clk(&priv->clk.dev);
267 	if (ret) {
268 		printf("Crypto-v1: failed to get clk device, ret=%d\n", ret);
269 		return ret;
270 	}
271 
272 	clocks = (u32 *)priv->clocks;
273 	for (i = 1; i < priv->nclocks; i += 2) {
274 		priv->clk.id = clocks[i];
275 		ret = clk_set_rate(&priv->clk, priv->frequency);
276 		if (ret < 0) {
277 			printf("Crypto-v1: failed to set clk(%ld): ret=%d\n",
278 			       priv->clk.id, ret);
279 			return ret;
280 		}
281 	}
282 
283 	return 0;
284 }
285 
286 static const struct udevice_id rockchip_crypto_ids[] = {
287 	{ .compatible = "rockchip,rk3399-crypto" },
288 	{ .compatible = "rockchip,rk3368-crypto" },
289 	{ .compatible = "rockchip,rk3328-crypto" },
290 	{ .compatible = "rockchip,rk3288-crypto" },
291 	{ .compatible = "rockchip,rk322x-crypto" },
292 	{ .compatible = "rockchip,rk312x-crypto" },
293 	{ }
294 };
295 
296 U_BOOT_DRIVER(rockchip_crypto_v1) = {
297 	.name		= "rockchip_crypto_v1",
298 	.id		= UCLASS_CRYPTO,
299 	.of_match	= rockchip_crypto_ids,
300 	.ops		= &rockchip_crypto_ops,
301 	.probe		= rockchip_crypto_probe,
302 	.ofdata_to_platdata = rockchip_crypto_ofdata_to_platdata,
303 	.priv_auto_alloc_size = sizeof(struct rockchip_crypto_priv),
304 };
305