xref: /rk3399_rockchip-uboot/drivers/crypto/rockchip/crypto_v1.c (revision 14ce00ea6054d950077c021d7b484c52dc54399f)
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 aligned\n");
109 		return -EINVAL;
110 	}
111 
112 	/* Must flush dcache before crypto DMA fetch data region */
113 	aligned_input = round_down((ulong)input, CONFIG_SYS_CACHELINE_SIZE);
114 	aligned_len = round_up(len + ((ulong)input - aligned_input),
115 			       CONFIG_SYS_CACHELINE_SIZE);
116 	flush_cache(aligned_input, aligned_len);
117 
118 	/* Wait last complete */
119 	do {} while (readl(&reg->crypto_ctrl) & HASH_START);
120 
121 	/* Hash Done Interrupt */
122 	writel(HASH_DONE_INT, &reg->crypto_intsts);
123 
124 	/* Set data base and length */
125 	writel((u32)(ulong)input, &reg->crypto_hrdmas);
126 	writel((len + 3) >> 2, &reg->crypto_hrdmal);
127 
128 	/* Write 1 to start. When finishes, the core will clear it */
129 	rk_setreg(&reg->crypto_ctrl, HASH_START);
130 
131 	return 0;
132 }
133 
134 static int rockchip_crypto_sha_final(struct udevice *dev,
135 				     sha_context *ctx, u8 *output)
136 {
137 	struct rockchip_crypto_priv *priv = dev_get_priv(dev);
138 	struct rk_crypto_reg *reg = priv->reg;
139 	u32 *buf = (u32 *)output;
140 	u32 nbits;
141 	int i;
142 
143 	if (priv->length != ctx->length) {
144 		printf("Crypto-v1: data total length(0x%08x) != init length(0x%08x)!\n",
145 		       priv->length, ctx->length);
146 		return -EIO;
147 	}
148 
149 	/* Wait last complete */
150 	do {} while (readl(&reg->crypto_ctrl) & HASH_START);
151 
152 	/* It is high when finish, and it will not be low until it restart */
153 	do {} while (!readl(&reg->crypto_hash_sts));
154 
155 	/* Read hash data, per-data 32-bit */
156 	nbits = crypto_algo_nbits(ctx->algo);
157 	for (i = 0; i < BITS2WORD(nbits); i++)
158 		buf[i] = readl(&reg->crypto_hash_dout[i]);
159 
160 	return 0;
161 }
162 
163 static int rockchip_crypto_rsa_verify(struct udevice *dev, rsa_key *ctx,
164 				      u8 *sign, u8 *output)
165 {
166 	struct rockchip_crypto_priv *priv = dev_get_priv(dev);
167 	struct rk_crypto_reg *reg = priv->reg;
168 	u32 nbits, *buf = (u32 *)output;
169 	int i, value;
170 
171 	if (!ctx)
172 		return -EINVAL;
173 
174 	if (ctx->algo == CRYPTO_RSA512)
175 		value = PKA_BLOCK_SIZE_512;
176 	else if (ctx->algo == CRYPTO_RSA1024)
177 		value = PKA_BLOCK_SIZE_1024;
178 	else if (ctx->algo == CRYPTO_RSA2048)
179 		value = PKA_BLOCK_SIZE_2048;
180 	else
181 		return -EINVAL;
182 
183 	/* Specify the nbits of N in PKA calculation */
184 	writel(value, &reg->crypto_pka_ctrl);
185 
186 	/* Flush SHA and RSA */
187 	rk_setreg(&reg->crypto_ctrl, PKA_HASH_CTRL);
188 	writel(0xffffffff, &reg->crypto_intsts);
189 	do {} while (readl(&reg->crypto_ctrl) & PKA_CTRL);
190 
191 	/* Clean PKA done interrupt */
192 	writel(PKA_DONE_INT, &reg->crypto_intsts);
193 
194 	/* Set m/n/e/c */
195 	nbits = crypto_algo_nbits(ctx->algo);
196 	memcpy((void *)&reg->crypto_pka_m, (void *)sign,   BITS2BYTE(nbits));
197 	memcpy((void *)&reg->crypto_pka_n, (void *)ctx->n, BITS2BYTE(nbits));
198 	memcpy((void *)&reg->crypto_pka_e, (void *)ctx->e, BITS2BYTE(nbits));
199 	memcpy((void *)&reg->crypto_pka_c, (void *)ctx->c, BITS2BYTE(nbits));
200 	do {} while (readl(&reg->crypto_ctrl) & PKA_START);
201 
202 	/* Start PKA */
203 	rk_setreg(&reg->crypto_ctrl, PKA_START);
204 
205 	/* Wait PKA done */
206 	do {} while (readl(&reg->crypto_ctrl) & PKA_START);
207 
208 	/* Read hash data, per-data 32-bit */
209 	for (i = 0; i < BITS2WORD(nbits); i++)
210 		buf[i] = readl(&reg->crypto_pka_m[i]);
211 
212 	return 0;
213 }
214 
215 static const struct dm_crypto_ops rockchip_crypto_ops = {
216 	.capability = rockchip_crypto_capability,
217 	.sha_init   = rockchip_crypto_sha_init,
218 	.sha_update = rockchip_crypto_sha_update,
219 	.sha_final  = rockchip_crypto_sha_final,
220 	.rsa_verify = rockchip_crypto_rsa_verify,
221 };
222 
223 /*
224  * Only use "clocks" to parse crypto clock id and use rockchip_get_clk().
225  * Because we always add crypto node in U-Boot dts, when kernel dtb enabled :
226  *
227  *   1. There is cru phandle mismatch between U-Boot and kernel dtb;
228  *   2. CONFIG_OF_SPL_REMOVE_PROPS removes clock property;
229  */
230 static int rockchip_crypto_ofdata_to_platdata(struct udevice *dev)
231 {
232 	struct rockchip_crypto_priv *priv = dev_get_priv(dev);
233 	int len;
234 
235 	if (!dev_read_prop(dev, "clocks", &len)) {
236 		printf("Crypto-v1: can't find \"clocks\" property\n");
237 		return -EINVAL;
238 	}
239 
240 	priv->clocks = malloc(len);
241 	if (!priv->clocks)
242 		return -ENOMEM;
243 
244 	priv->nclocks = len / sizeof(u32);
245 	if (dev_read_u32_array(dev, "clocks", (u32 *)priv->clocks,
246 			       priv->nclocks)) {
247 		printf("Crypto-v1: can't read \"clocks\" property\n");
248 		return -EINVAL;
249 	}
250 
251 	priv->reg = dev_read_addr_ptr(dev);
252 	priv->frequency = dev_read_u32_default(dev, "clock-frequency",
253 					       CRYPTO_V1_DEFAULT_RATE);
254 
255 	return 0;
256 }
257 
258 static int rockchip_crypto_probe(struct udevice *dev)
259 {
260 	struct rockchip_crypto_priv *priv = dev_get_priv(dev);
261 	u32 *clocks;
262 	int i, ret;
263 
264 	ret = rockchip_get_clk(&priv->clk.dev);
265 	if (ret) {
266 		printf("Crypto-v1: failed to get clk device, ret=%d\n", ret);
267 		return ret;
268 	}
269 
270 	clocks = (u32 *)priv->clocks;
271 	for (i = 1; i < priv->nclocks; i += 2) {
272 		priv->clk.id = clocks[i];
273 		ret = clk_set_rate(&priv->clk, priv->frequency);
274 		if (ret < 0) {
275 			printf("Crypto-v1: failed to set clk(%ld): ret=%d\n",
276 			       priv->clk.id, ret);
277 			return ret;
278 		}
279 	}
280 
281 	return 0;
282 }
283 
284 static const struct udevice_id rockchip_crypto_ids[] = {
285 	{ .compatible = "rockchip,rk3399-crypto" },
286 	{ .compatible = "rockchip,rk3368-crypto" },
287 	{ .compatible = "rockchip,rk3328-crypto" },
288 	{ .compatible = "rockchip,rk3288-crypto" },
289 	{ .compatible = "rockchip,rk322x-crypto" },
290 	{ .compatible = "rockchip,rk312x-crypto" },
291 	{ }
292 };
293 
294 U_BOOT_DRIVER(rockchip_crypto_v1) = {
295 	.name		= "rockchip_crypto_v1",
296 	.id		= UCLASS_CRYPTO,
297 	.of_match	= rockchip_crypto_ids,
298 	.ops		= &rockchip_crypto_ops,
299 	.probe		= rockchip_crypto_probe,
300 	.ofdata_to_platdata = rockchip_crypto_ofdata_to_platdata,
301 	.priv_auto_alloc_size = sizeof(struct rockchip_crypto_priv),
302 };
303