Commit | Line | Data |
---|---|---|
f08fcced CL |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * sun8i-ss-core.c - hardware cryptographic offloader for | |
4 | * Allwinner A80/A83T SoC | |
5 | * | |
6 | * Copyright (C) 2015-2019 Corentin Labbe <clabbe.montjoie@gmail.com> | |
7 | * | |
8 | * Core file which registers crypto algorithms supported by the SecuritySystem | |
9 | * | |
10 | * You could find a link for the datasheet in Documentation/arm/sunxi/README | |
11 | */ | |
12 | #include <linux/clk.h> | |
13 | #include <linux/crypto.h> | |
14 | #include <linux/delay.h> | |
15 | #include <linux/dma-mapping.h> | |
16 | #include <linux/interrupt.h> | |
17 | #include <linux/io.h> | |
18 | #include <linux/irq.h> | |
19 | #include <linux/module.h> | |
20 | #include <linux/of.h> | |
21 | #include <linux/of_device.h> | |
22 | #include <linux/platform_device.h> | |
23 | #include <linux/pm_runtime.h> | |
24 | #include <linux/reset.h> | |
25 | #include <crypto/internal/skcipher.h> | |
26 | ||
27 | #include "sun8i-ss.h" | |
28 | ||
29 | static const struct ss_variant ss_a80_variant = { | |
30 | .alg_cipher = { SS_ALG_AES, SS_ALG_DES, SS_ALG_3DES, | |
31 | }, | |
32 | .op_mode = { SS_OP_ECB, SS_OP_CBC, | |
33 | }, | |
34 | .ss_clks = { | |
35 | { "bus", 0, 300 * 1000 * 1000 }, | |
36 | { "mod", 0, 300 * 1000 * 1000 }, | |
37 | } | |
38 | }; | |
39 | ||
40 | static const struct ss_variant ss_a83t_variant = { | |
41 | .alg_cipher = { SS_ALG_AES, SS_ALG_DES, SS_ALG_3DES, | |
42 | }, | |
43 | .op_mode = { SS_OP_ECB, SS_OP_CBC, | |
44 | }, | |
45 | .ss_clks = { | |
46 | { "bus", 0, 300 * 1000 * 1000 }, | |
47 | { "mod", 0, 300 * 1000 * 1000 }, | |
48 | } | |
49 | }; | |
50 | ||
51 | /* | |
52 | * sun8i_ss_get_engine_number() get the next channel slot | |
53 | * This is a simple round-robin way of getting the next channel | |
54 | */ | |
55 | int sun8i_ss_get_engine_number(struct sun8i_ss_dev *ss) | |
56 | { | |
57 | return atomic_inc_return(&ss->flow) % MAXFLOW; | |
58 | } | |
59 | ||
60 | int sun8i_ss_run_task(struct sun8i_ss_dev *ss, struct sun8i_cipher_req_ctx *rctx, | |
61 | const char *name) | |
62 | { | |
63 | int flow = rctx->flow; | |
64 | u32 v = 1; | |
65 | int i; | |
66 | ||
67 | #ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG | |
68 | ss->flows[flow].stat_req++; | |
69 | #endif | |
70 | ||
71 | /* choose between stream0/stream1 */ | |
72 | if (flow) | |
73 | v |= SS_FLOW1; | |
74 | else | |
75 | v |= SS_FLOW0; | |
76 | ||
77 | v |= rctx->op_mode; | |
78 | v |= rctx->method; | |
79 | ||
80 | if (rctx->op_dir) | |
81 | v |= SS_DECRYPTION; | |
82 | ||
83 | switch (rctx->keylen) { | |
84 | case 128 / 8: | |
85 | v |= SS_AES_128BITS << 7; | |
86 | break; | |
87 | case 192 / 8: | |
88 | v |= SS_AES_192BITS << 7; | |
89 | break; | |
90 | case 256 / 8: | |
91 | v |= SS_AES_256BITS << 7; | |
92 | break; | |
93 | } | |
94 | ||
95 | for (i = 0; i < MAX_SG; i++) { | |
96 | if (!rctx->t_dst[i].addr) | |
97 | break; | |
98 | ||
99 | mutex_lock(&ss->mlock); | |
100 | writel(rctx->p_key, ss->base + SS_KEY_ADR_REG); | |
101 | ||
102 | if (i == 0) { | |
103 | if (rctx->p_iv) | |
104 | writel(rctx->p_iv, ss->base + SS_IV_ADR_REG); | |
105 | } else { | |
106 | if (rctx->biv) { | |
107 | if (rctx->op_dir == SS_ENCRYPTION) | |
108 | writel(rctx->t_dst[i - 1].addr + rctx->t_dst[i - 1].len * 4 - rctx->ivlen, ss->base + SS_IV_ADR_REG); | |
109 | else | |
110 | writel(rctx->t_src[i - 1].addr + rctx->t_src[i - 1].len * 4 - rctx->ivlen, ss->base + SS_IV_ADR_REG); | |
111 | } | |
112 | } | |
113 | ||
114 | dev_dbg(ss->dev, | |
115 | "Processing SG %d on flow %d %s ctl=%x %d to %d method=%x opmode=%x opdir=%x srclen=%d\n", | |
116 | i, flow, name, v, | |
117 | rctx->t_src[i].len, rctx->t_dst[i].len, | |
118 | rctx->method, rctx->op_mode, | |
119 | rctx->op_dir, rctx->t_src[i].len); | |
120 | ||
121 | writel(rctx->t_src[i].addr, ss->base + SS_SRC_ADR_REG); | |
122 | writel(rctx->t_dst[i].addr, ss->base + SS_DST_ADR_REG); | |
123 | writel(rctx->t_src[i].len, ss->base + SS_LEN_ADR_REG); | |
124 | ||
125 | reinit_completion(&ss->flows[flow].complete); | |
126 | ss->flows[flow].status = 0; | |
127 | wmb(); | |
128 | ||
129 | writel(v, ss->base + SS_CTL_REG); | |
130 | mutex_unlock(&ss->mlock); | |
131 | wait_for_completion_interruptible_timeout(&ss->flows[flow].complete, | |
132 | msecs_to_jiffies(2000)); | |
133 | if (ss->flows[flow].status == 0) { | |
134 | dev_err(ss->dev, "DMA timeout for %s\n", name); | |
135 | return -EFAULT; | |
136 | } | |
137 | } | |
138 | ||
139 | return 0; | |
140 | } | |
141 | ||
142 | static irqreturn_t ss_irq_handler(int irq, void *data) | |
143 | { | |
144 | struct sun8i_ss_dev *ss = (struct sun8i_ss_dev *)data; | |
145 | int flow = 0; | |
146 | u32 p; | |
147 | ||
148 | p = readl(ss->base + SS_INT_STA_REG); | |
149 | for (flow = 0; flow < MAXFLOW; flow++) { | |
150 | if (p & (BIT(flow))) { | |
151 | writel(BIT(flow), ss->base + SS_INT_STA_REG); | |
152 | ss->flows[flow].status = 1; | |
153 | complete(&ss->flows[flow].complete); | |
154 | } | |
155 | } | |
156 | ||
157 | return IRQ_HANDLED; | |
158 | } | |
159 | ||
160 | static struct sun8i_ss_alg_template ss_algs[] = { | |
161 | { | |
162 | .type = CRYPTO_ALG_TYPE_SKCIPHER, | |
163 | .ss_algo_id = SS_ID_CIPHER_AES, | |
164 | .ss_blockmode = SS_ID_OP_CBC, | |
165 | .alg.skcipher = { | |
166 | .base = { | |
167 | .cra_name = "cbc(aes)", | |
168 | .cra_driver_name = "cbc-aes-sun8i-ss", | |
169 | .cra_priority = 400, | |
170 | .cra_blocksize = AES_BLOCK_SIZE, | |
171 | .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | | |
172 | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, | |
173 | .cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx), | |
174 | .cra_module = THIS_MODULE, | |
175 | .cra_alignmask = 0xf, | |
176 | .cra_init = sun8i_ss_cipher_init, | |
177 | .cra_exit = sun8i_ss_cipher_exit, | |
178 | }, | |
179 | .min_keysize = AES_MIN_KEY_SIZE, | |
180 | .max_keysize = AES_MAX_KEY_SIZE, | |
181 | .ivsize = AES_BLOCK_SIZE, | |
182 | .setkey = sun8i_ss_aes_setkey, | |
183 | .encrypt = sun8i_ss_skencrypt, | |
184 | .decrypt = sun8i_ss_skdecrypt, | |
185 | } | |
186 | }, | |
187 | { | |
188 | .type = CRYPTO_ALG_TYPE_SKCIPHER, | |
189 | .ss_algo_id = SS_ID_CIPHER_AES, | |
190 | .ss_blockmode = SS_ID_OP_ECB, | |
191 | .alg.skcipher = { | |
192 | .base = { | |
193 | .cra_name = "ecb(aes)", | |
194 | .cra_driver_name = "ecb-aes-sun8i-ss", | |
195 | .cra_priority = 400, | |
196 | .cra_blocksize = AES_BLOCK_SIZE, | |
197 | .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | | |
198 | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, | |
199 | .cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx), | |
200 | .cra_module = THIS_MODULE, | |
201 | .cra_alignmask = 0xf, | |
202 | .cra_init = sun8i_ss_cipher_init, | |
203 | .cra_exit = sun8i_ss_cipher_exit, | |
204 | }, | |
205 | .min_keysize = AES_MIN_KEY_SIZE, | |
206 | .max_keysize = AES_MAX_KEY_SIZE, | |
207 | .setkey = sun8i_ss_aes_setkey, | |
208 | .encrypt = sun8i_ss_skencrypt, | |
209 | .decrypt = sun8i_ss_skdecrypt, | |
210 | } | |
211 | }, | |
212 | { | |
213 | .type = CRYPTO_ALG_TYPE_SKCIPHER, | |
214 | .ss_algo_id = SS_ID_CIPHER_DES3, | |
215 | .ss_blockmode = SS_ID_OP_CBC, | |
216 | .alg.skcipher = { | |
217 | .base = { | |
218 | .cra_name = "cbc(des3_ede)", | |
219 | .cra_driver_name = "cbc-des3-sun8i-ss", | |
220 | .cra_priority = 400, | |
221 | .cra_blocksize = DES3_EDE_BLOCK_SIZE, | |
222 | .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | | |
223 | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, | |
224 | .cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx), | |
225 | .cra_module = THIS_MODULE, | |
226 | .cra_alignmask = 0xf, | |
227 | .cra_init = sun8i_ss_cipher_init, | |
228 | .cra_exit = sun8i_ss_cipher_exit, | |
229 | }, | |
230 | .min_keysize = DES3_EDE_KEY_SIZE, | |
231 | .max_keysize = DES3_EDE_KEY_SIZE, | |
232 | .ivsize = DES3_EDE_BLOCK_SIZE, | |
233 | .setkey = sun8i_ss_des3_setkey, | |
234 | .encrypt = sun8i_ss_skencrypt, | |
235 | .decrypt = sun8i_ss_skdecrypt, | |
236 | } | |
237 | }, | |
238 | { | |
239 | .type = CRYPTO_ALG_TYPE_SKCIPHER, | |
240 | .ss_algo_id = SS_ID_CIPHER_DES3, | |
241 | .ss_blockmode = SS_ID_OP_ECB, | |
242 | .alg.skcipher = { | |
243 | .base = { | |
244 | .cra_name = "ecb(des3_ede)", | |
245 | .cra_driver_name = "ecb-des3-sun8i-ss", | |
246 | .cra_priority = 400, | |
247 | .cra_blocksize = DES3_EDE_BLOCK_SIZE, | |
248 | .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | | |
249 | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, | |
250 | .cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx), | |
251 | .cra_module = THIS_MODULE, | |
252 | .cra_alignmask = 0xf, | |
253 | .cra_init = sun8i_ss_cipher_init, | |
254 | .cra_exit = sun8i_ss_cipher_exit, | |
255 | }, | |
256 | .min_keysize = DES3_EDE_KEY_SIZE, | |
257 | .max_keysize = DES3_EDE_KEY_SIZE, | |
258 | .setkey = sun8i_ss_des3_setkey, | |
259 | .encrypt = sun8i_ss_skencrypt, | |
260 | .decrypt = sun8i_ss_skdecrypt, | |
261 | } | |
262 | }, | |
263 | }; | |
264 | ||
265 | #ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG | |
266 | static int sun8i_ss_dbgfs_read(struct seq_file *seq, void *v) | |
267 | { | |
268 | struct sun8i_ss_dev *ss = seq->private; | |
269 | int i; | |
270 | ||
271 | for (i = 0; i < MAXFLOW; i++) | |
272 | seq_printf(seq, "Channel %d: nreq %lu\n", i, ss->flows[i].stat_req); | |
273 | ||
274 | for (i = 0; i < ARRAY_SIZE(ss_algs); i++) { | |
275 | if (!ss_algs[i].ss) | |
276 | continue; | |
277 | switch (ss_algs[i].type) { | |
278 | case CRYPTO_ALG_TYPE_SKCIPHER: | |
279 | seq_printf(seq, "%s %s %lu %lu\n", | |
280 | ss_algs[i].alg.skcipher.base.cra_driver_name, | |
281 | ss_algs[i].alg.skcipher.base.cra_name, | |
282 | ss_algs[i].stat_req, ss_algs[i].stat_fb); | |
283 | break; | |
284 | } | |
285 | } | |
286 | return 0; | |
287 | } | |
288 | ||
289 | static int sun8i_ss_dbgfs_open(struct inode *inode, struct file *file) | |
290 | { | |
291 | return single_open(file, sun8i_ss_dbgfs_read, inode->i_private); | |
292 | } | |
293 | ||
294 | static const struct file_operations sun8i_ss_debugfs_fops = { | |
295 | .owner = THIS_MODULE, | |
296 | .open = sun8i_ss_dbgfs_open, | |
297 | .read = seq_read, | |
298 | .llseek = seq_lseek, | |
299 | .release = single_release, | |
300 | }; | |
301 | #endif | |
302 | ||
303 | static void sun8i_ss_free_flows(struct sun8i_ss_dev *ss, int i) | |
304 | { | |
305 | while (i >= 0) { | |
306 | crypto_engine_exit(ss->flows[i].engine); | |
307 | i--; | |
308 | } | |
309 | } | |
310 | ||
311 | /* | |
312 | * Allocate the flow list structure | |
313 | */ | |
314 | static int allocate_flows(struct sun8i_ss_dev *ss) | |
315 | { | |
316 | int i, err; | |
317 | ||
318 | ss->flows = devm_kcalloc(ss->dev, MAXFLOW, sizeof(struct sun8i_ss_flow), | |
319 | GFP_KERNEL); | |
320 | if (!ss->flows) | |
321 | return -ENOMEM; | |
322 | ||
323 | for (i = 0; i < MAXFLOW; i++) { | |
324 | init_completion(&ss->flows[i].complete); | |
325 | ||
326 | ss->flows[i].engine = crypto_engine_alloc_init(ss->dev, true); | |
327 | if (!ss->flows[i].engine) { | |
328 | dev_err(ss->dev, "Cannot allocate engine\n"); | |
329 | i--; | |
330 | err = -ENOMEM; | |
331 | goto error_engine; | |
332 | } | |
333 | err = crypto_engine_start(ss->flows[i].engine); | |
334 | if (err) { | |
335 | dev_err(ss->dev, "Cannot start engine\n"); | |
336 | goto error_engine; | |
337 | } | |
338 | } | |
339 | return 0; | |
340 | error_engine: | |
341 | sun8i_ss_free_flows(ss, i); | |
342 | return err; | |
343 | } | |
344 | ||
345 | /* | |
346 | * Power management strategy: The device is suspended unless a TFM exists for | |
347 | * one of the algorithms proposed by this driver. | |
348 | */ | |
349 | static int sun8i_ss_pm_suspend(struct device *dev) | |
350 | { | |
351 | struct sun8i_ss_dev *ss = dev_get_drvdata(dev); | |
352 | int i; | |
353 | ||
354 | reset_control_assert(ss->reset); | |
355 | for (i = 0; i < SS_MAX_CLOCKS; i++) | |
356 | clk_disable_unprepare(ss->ssclks[i]); | |
357 | return 0; | |
358 | } | |
359 | ||
360 | static int sun8i_ss_pm_resume(struct device *dev) | |
361 | { | |
362 | struct sun8i_ss_dev *ss = dev_get_drvdata(dev); | |
363 | int err, i; | |
364 | ||
365 | for (i = 0; i < SS_MAX_CLOCKS; i++) { | |
366 | if (!ss->variant->ss_clks[i].name) | |
367 | continue; | |
368 | err = clk_prepare_enable(ss->ssclks[i]); | |
369 | if (err) { | |
370 | dev_err(ss->dev, "Cannot prepare_enable %s\n", | |
371 | ss->variant->ss_clks[i].name); | |
372 | goto error; | |
373 | } | |
374 | } | |
375 | err = reset_control_deassert(ss->reset); | |
376 | if (err) { | |
377 | dev_err(ss->dev, "Cannot deassert reset control\n"); | |
378 | goto error; | |
379 | } | |
380 | /* enable interrupts for all flows */ | |
381 | writel(BIT(0) | BIT(1), ss->base + SS_INT_CTL_REG); | |
382 | ||
383 | return 0; | |
384 | error: | |
385 | sun8i_ss_pm_suspend(dev); | |
386 | return err; | |
387 | } | |
388 | ||
389 | static const struct dev_pm_ops sun8i_ss_pm_ops = { | |
390 | SET_RUNTIME_PM_OPS(sun8i_ss_pm_suspend, sun8i_ss_pm_resume, NULL) | |
391 | }; | |
392 | ||
393 | static int sun8i_ss_pm_init(struct sun8i_ss_dev *ss) | |
394 | { | |
395 | int err; | |
396 | ||
397 | pm_runtime_use_autosuspend(ss->dev); | |
398 | pm_runtime_set_autosuspend_delay(ss->dev, 2000); | |
399 | ||
400 | err = pm_runtime_set_suspended(ss->dev); | |
401 | if (err) | |
402 | return err; | |
403 | pm_runtime_enable(ss->dev); | |
404 | return err; | |
405 | } | |
406 | ||
407 | static void sun8i_ss_pm_exit(struct sun8i_ss_dev *ss) | |
408 | { | |
409 | pm_runtime_disable(ss->dev); | |
410 | } | |
411 | ||
412 | static int sun8i_ss_register_algs(struct sun8i_ss_dev *ss) | |
413 | { | |
414 | int ss_method, err, id, i; | |
415 | ||
416 | for (i = 0; i < ARRAY_SIZE(ss_algs); i++) { | |
417 | ss_algs[i].ss = ss; | |
418 | switch (ss_algs[i].type) { | |
419 | case CRYPTO_ALG_TYPE_SKCIPHER: | |
420 | id = ss_algs[i].ss_algo_id; | |
421 | ss_method = ss->variant->alg_cipher[id]; | |
422 | if (ss_method == SS_ID_NOTSUPP) { | |
423 | dev_info(ss->dev, | |
424 | "DEBUG: Algo of %s not supported\n", | |
425 | ss_algs[i].alg.skcipher.base.cra_name); | |
426 | ss_algs[i].ss = NULL; | |
427 | break; | |
428 | } | |
429 | id = ss_algs[i].ss_blockmode; | |
430 | ss_method = ss->variant->op_mode[id]; | |
431 | if (ss_method == SS_ID_NOTSUPP) { | |
432 | dev_info(ss->dev, "DEBUG: Blockmode of %s not supported\n", | |
433 | ss_algs[i].alg.skcipher.base.cra_name); | |
434 | ss_algs[i].ss = NULL; | |
435 | break; | |
436 | } | |
437 | dev_info(ss->dev, "DEBUG: Register %s\n", | |
438 | ss_algs[i].alg.skcipher.base.cra_name); | |
439 | err = crypto_register_skcipher(&ss_algs[i].alg.skcipher); | |
440 | if (err) { | |
441 | dev_err(ss->dev, "Fail to register %s\n", | |
442 | ss_algs[i].alg.skcipher.base.cra_name); | |
443 | ss_algs[i].ss = NULL; | |
444 | return err; | |
445 | } | |
446 | break; | |
447 | default: | |
448 | ss_algs[i].ss = NULL; | |
449 | dev_err(ss->dev, "ERROR: tryed to register an unknown algo\n"); | |
450 | } | |
451 | } | |
452 | return 0; | |
453 | } | |
454 | ||
455 | static void sun8i_ss_unregister_algs(struct sun8i_ss_dev *ss) | |
456 | { | |
457 | int i; | |
458 | ||
459 | for (i = 0; i < ARRAY_SIZE(ss_algs); i++) { | |
460 | if (!ss_algs[i].ss) | |
461 | continue; | |
462 | switch (ss_algs[i].type) { | |
463 | case CRYPTO_ALG_TYPE_SKCIPHER: | |
464 | dev_info(ss->dev, "Unregister %d %s\n", i, | |
465 | ss_algs[i].alg.skcipher.base.cra_name); | |
466 | crypto_unregister_skcipher(&ss_algs[i].alg.skcipher); | |
467 | break; | |
468 | } | |
469 | } | |
470 | } | |
471 | ||
472 | static int sun8i_ss_get_clks(struct sun8i_ss_dev *ss) | |
473 | { | |
474 | unsigned long cr; | |
475 | int err, i; | |
476 | ||
477 | for (i = 0; i < SS_MAX_CLOCKS; i++) { | |
478 | if (!ss->variant->ss_clks[i].name) | |
479 | continue; | |
480 | ss->ssclks[i] = devm_clk_get(ss->dev, ss->variant->ss_clks[i].name); | |
481 | if (IS_ERR(ss->ssclks[i])) { | |
482 | err = PTR_ERR(ss->ssclks[i]); | |
483 | dev_err(ss->dev, "Cannot get %s SS clock err=%d\n", | |
484 | ss->variant->ss_clks[i].name, err); | |
485 | return err; | |
486 | } | |
487 | cr = clk_get_rate(ss->ssclks[i]); | |
488 | if (!cr) | |
489 | return -EINVAL; | |
490 | if (ss->variant->ss_clks[i].freq > 0 && | |
491 | cr != ss->variant->ss_clks[i].freq) { | |
492 | dev_info(ss->dev, "Set %s clock to %lu (%lu Mhz) from %lu (%lu Mhz)\n", | |
493 | ss->variant->ss_clks[i].name, | |
494 | ss->variant->ss_clks[i].freq, | |
495 | ss->variant->ss_clks[i].freq / 1000000, | |
496 | cr, cr / 1000000); | |
497 | err = clk_set_rate(ss->ssclks[i], ss->variant->ss_clks[i].freq); | |
498 | if (err) | |
499 | dev_err(ss->dev, "Fail to set %s clk speed to %lu hz\n", | |
500 | ss->variant->ss_clks[i].name, | |
501 | ss->variant->ss_clks[i].freq); | |
502 | } | |
503 | if (ss->variant->ss_clks[i].max_freq > 0 && | |
504 | cr > ss->variant->ss_clks[i].max_freq) | |
505 | dev_warn(ss->dev, "Frequency for %s (%lu hz) is higher than datasheet's recommandation (%lu hz)", | |
506 | ss->variant->ss_clks[i].name, cr, | |
507 | ss->variant->ss_clks[i].max_freq); | |
508 | } | |
509 | return 0; | |
510 | } | |
511 | ||
512 | static int sun8i_ss_probe(struct platform_device *pdev) | |
513 | { | |
514 | struct sun8i_ss_dev *ss; | |
515 | int err, irq; | |
516 | u32 v; | |
517 | ||
518 | ss = devm_kzalloc(&pdev->dev, sizeof(*ss), GFP_KERNEL); | |
519 | if (!ss) | |
520 | return -ENOMEM; | |
521 | ||
522 | ss->dev = &pdev->dev; | |
523 | platform_set_drvdata(pdev, ss); | |
524 | ||
525 | ss->variant = of_device_get_match_data(&pdev->dev); | |
526 | if (!ss->variant) { | |
527 | dev_err(&pdev->dev, "Missing Crypto Engine variant\n"); | |
528 | return -EINVAL; | |
529 | } | |
530 | ||
09b68164 | 531 | ss->base = devm_platform_ioremap_resource(pdev, 0); |
f08fcced CL |
532 | if (IS_ERR(ss->base)) |
533 | return PTR_ERR(ss->base); | |
534 | ||
535 | err = sun8i_ss_get_clks(ss); | |
536 | if (err) | |
537 | return err; | |
538 | ||
539 | irq = platform_get_irq(pdev, 0); | |
540 | if (irq < 0) { | |
541 | dev_err(ss->dev, "Cannot get SecuritySystem IRQ\n"); | |
542 | return irq; | |
543 | } | |
544 | ||
545 | ss->reset = devm_reset_control_get(&pdev->dev, NULL); | |
546 | if (IS_ERR(ss->reset)) { | |
547 | if (PTR_ERR(ss->reset) == -EPROBE_DEFER) | |
548 | return PTR_ERR(ss->reset); | |
549 | dev_err(&pdev->dev, "No reset control found\n"); | |
550 | return PTR_ERR(ss->reset); | |
551 | } | |
552 | ||
553 | mutex_init(&ss->mlock); | |
554 | ||
555 | err = allocate_flows(ss); | |
556 | if (err) | |
557 | return err; | |
558 | ||
559 | err = sun8i_ss_pm_init(ss); | |
560 | if (err) | |
561 | goto error_pm; | |
562 | ||
563 | err = devm_request_irq(&pdev->dev, irq, ss_irq_handler, 0, "sun8i-ss", ss); | |
564 | if (err) { | |
565 | dev_err(ss->dev, "Cannot request SecuritySystem IRQ (err=%d)\n", err); | |
566 | goto error_irq; | |
567 | } | |
568 | ||
569 | err = sun8i_ss_register_algs(ss); | |
570 | if (err) | |
571 | goto error_alg; | |
572 | ||
573 | err = pm_runtime_get_sync(ss->dev); | |
574 | if (err < 0) | |
575 | goto error_alg; | |
576 | ||
577 | v = readl(ss->base + SS_CTL_REG); | |
578 | v >>= SS_DIE_ID_SHIFT; | |
579 | v &= SS_DIE_ID_MASK; | |
580 | dev_info(&pdev->dev, "Security System Die ID %x\n", v); | |
581 | ||
582 | pm_runtime_put_sync(ss->dev); | |
583 | ||
584 | #ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG | |
585 | /* Ignore error of debugfs */ | |
586 | ss->dbgfs_dir = debugfs_create_dir("sun8i-ss", NULL); | |
587 | ss->dbgfs_stats = debugfs_create_file("stats", 0444, | |
588 | ss->dbgfs_dir, ss, | |
589 | &sun8i_ss_debugfs_fops); | |
590 | #endif | |
591 | ||
592 | return 0; | |
593 | error_alg: | |
594 | sun8i_ss_unregister_algs(ss); | |
595 | error_irq: | |
596 | sun8i_ss_pm_exit(ss); | |
597 | error_pm: | |
598 | sun8i_ss_free_flows(ss, MAXFLOW); | |
599 | return err; | |
600 | } | |
601 | ||
602 | static int sun8i_ss_remove(struct platform_device *pdev) | |
603 | { | |
604 | struct sun8i_ss_dev *ss = platform_get_drvdata(pdev); | |
605 | ||
606 | sun8i_ss_unregister_algs(ss); | |
607 | ||
608 | #ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG | |
609 | debugfs_remove_recursive(ss->dbgfs_dir); | |
610 | #endif | |
611 | ||
612 | sun8i_ss_free_flows(ss, MAXFLOW); | |
613 | ||
614 | sun8i_ss_pm_exit(ss); | |
615 | ||
616 | return 0; | |
617 | } | |
618 | ||
619 | static const struct of_device_id sun8i_ss_crypto_of_match_table[] = { | |
620 | { .compatible = "allwinner,sun8i-a83t-crypto", | |
621 | .data = &ss_a83t_variant }, | |
622 | { .compatible = "allwinner,sun9i-a80-crypto", | |
623 | .data = &ss_a80_variant }, | |
624 | {} | |
625 | }; | |
626 | MODULE_DEVICE_TABLE(of, sun8i_ss_crypto_of_match_table); | |
627 | ||
628 | static struct platform_driver sun8i_ss_driver = { | |
629 | .probe = sun8i_ss_probe, | |
630 | .remove = sun8i_ss_remove, | |
631 | .driver = { | |
632 | .name = "sun8i-ss", | |
633 | .pm = &sun8i_ss_pm_ops, | |
634 | .of_match_table = sun8i_ss_crypto_of_match_table, | |
635 | }, | |
636 | }; | |
637 | ||
638 | module_platform_driver(sun8i_ss_driver); | |
639 | ||
640 | MODULE_DESCRIPTION("Allwinner SecuritySystem cryptographic offloader"); | |
641 | MODULE_LICENSE("GPL"); | |
642 | MODULE_AUTHOR("Corentin Labbe <clabbe.montjoie@gmail.com>"); |