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