1 // SPDX-License-Identifier: GPL-2.0-only
3 * Crypto acceleration support for Rockchip RK3288
5 * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd
7 * Author: Zain Wang <zain.wang@rock-chips.com>
9 * Some ideas are from marvell-cesa.c and s5p-sss.c driver.
12 #include "rk3288_crypto.h"
13 #include <crypto/engine.h>
14 #include <crypto/internal/hash.h>
15 #include <crypto/internal/skcipher.h>
16 #include <linux/clk.h>
17 #include <linux/dma-mapping.h>
18 #include <linux/debugfs.h>
19 #include <linux/delay.h>
20 #include <linux/err.h>
21 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/platform_device.h>
26 #include <linux/reset.h>
27 #include <linux/spinlock.h>
29 static struct rockchip_ip rocklist
= {
30 .dev_list
= LIST_HEAD_INIT(rocklist
.dev_list
),
31 .lock
= __SPIN_LOCK_UNLOCKED(rocklist
.lock
),
34 struct rk_crypto_info
*get_rk_crypto(void)
36 struct rk_crypto_info
*first
;
38 spin_lock(&rocklist
.lock
);
39 first
= list_first_entry_or_null(&rocklist
.dev_list
,
40 struct rk_crypto_info
, list
);
41 list_rotate_left(&rocklist
.dev_list
);
42 spin_unlock(&rocklist
.lock
);
46 static const struct rk_variant rk3288_variant
= {
53 static const struct rk_variant rk3328_variant
= {
57 static const struct rk_variant rk3399_variant
= {
61 static int rk_crypto_get_clks(struct rk_crypto_info
*dev
)
66 dev
->num_clks
= devm_clk_bulk_get_all(dev
->dev
, &dev
->clks
);
67 if (dev
->num_clks
< dev
->variant
->num_clks
) {
68 dev_err(dev
->dev
, "Missing clocks, got %d instead of %d\n",
69 dev
->num_clks
, dev
->variant
->num_clks
);
73 for (i
= 0; i
< dev
->num_clks
; i
++) {
74 cr
= clk_get_rate(dev
->clks
[i
].clk
);
75 for (j
= 0; j
< ARRAY_SIZE(dev
->variant
->rkclks
); j
++) {
76 if (dev
->variant
->rkclks
[j
].max
== 0)
78 if (strcmp(dev
->variant
->rkclks
[j
].name
, dev
->clks
[i
].id
))
80 if (cr
> dev
->variant
->rkclks
[j
].max
) {
81 err
= clk_set_rate(dev
->clks
[i
].clk
,
82 dev
->variant
->rkclks
[j
].max
);
84 dev_err(dev
->dev
, "Fail downclocking %s from %lu to %lu\n",
85 dev
->variant
->rkclks
[j
].name
, cr
,
86 dev
->variant
->rkclks
[j
].max
);
88 dev_info(dev
->dev
, "Downclocking %s from %lu to %lu\n",
89 dev
->variant
->rkclks
[j
].name
, cr
,
90 dev
->variant
->rkclks
[j
].max
);
97 static int rk_crypto_enable_clk(struct rk_crypto_info
*dev
)
101 err
= clk_bulk_prepare_enable(dev
->num_clks
, dev
->clks
);
103 dev_err(dev
->dev
, "Could not enable clock clks\n");
108 static void rk_crypto_disable_clk(struct rk_crypto_info
*dev
)
110 clk_bulk_disable_unprepare(dev
->num_clks
, dev
->clks
);
114 * Power management strategy: The device is suspended until a request
115 * is handled. For avoiding suspend/resume yoyo, the autosuspend is set to 2s.
117 static int rk_crypto_pm_suspend(struct device
*dev
)
119 struct rk_crypto_info
*rkdev
= dev_get_drvdata(dev
);
121 rk_crypto_disable_clk(rkdev
);
122 reset_control_assert(rkdev
->rst
);
127 static int rk_crypto_pm_resume(struct device
*dev
)
129 struct rk_crypto_info
*rkdev
= dev_get_drvdata(dev
);
132 ret
= rk_crypto_enable_clk(rkdev
);
136 reset_control_deassert(rkdev
->rst
);
141 static const struct dev_pm_ops rk_crypto_pm_ops
= {
142 SET_RUNTIME_PM_OPS(rk_crypto_pm_suspend
, rk_crypto_pm_resume
, NULL
)
145 static int rk_crypto_pm_init(struct rk_crypto_info
*rkdev
)
149 pm_runtime_use_autosuspend(rkdev
->dev
);
150 pm_runtime_set_autosuspend_delay(rkdev
->dev
, 2000);
152 err
= pm_runtime_set_suspended(rkdev
->dev
);
155 pm_runtime_enable(rkdev
->dev
);
159 static void rk_crypto_pm_exit(struct rk_crypto_info
*rkdev
)
161 pm_runtime_disable(rkdev
->dev
);
164 static irqreturn_t
rk_crypto_irq_handle(int irq
, void *dev_id
)
166 struct rk_crypto_info
*dev
= platform_get_drvdata(dev_id
);
167 u32 interrupt_status
;
169 interrupt_status
= CRYPTO_READ(dev
, RK_CRYPTO_INTSTS
);
170 CRYPTO_WRITE(dev
, RK_CRYPTO_INTSTS
, interrupt_status
);
173 if (interrupt_status
& 0x0a) {
174 dev_warn(dev
->dev
, "DMA Error\n");
177 complete(&dev
->complete
);
182 static struct rk_crypto_tmp
*rk_cipher_algs
[] = {
187 &rk_ecb_des3_ede_alg
,
188 &rk_cbc_des3_ede_alg
,
194 static int rk_crypto_debugfs_show(struct seq_file
*seq
, void *v
)
196 struct rk_crypto_info
*dd
;
199 spin_lock(&rocklist
.lock
);
200 list_for_each_entry(dd
, &rocklist
.dev_list
, list
) {
201 seq_printf(seq
, "%s %s requests: %lu\n",
202 dev_driver_string(dd
->dev
), dev_name(dd
->dev
),
205 spin_unlock(&rocklist
.lock
);
207 for (i
= 0; i
< ARRAY_SIZE(rk_cipher_algs
); i
++) {
208 if (!rk_cipher_algs
[i
]->dev
)
210 switch (rk_cipher_algs
[i
]->type
) {
211 case CRYPTO_ALG_TYPE_SKCIPHER
:
212 seq_printf(seq
, "%s %s reqs=%lu fallback=%lu\n",
213 rk_cipher_algs
[i
]->alg
.skcipher
.base
.base
.cra_driver_name
,
214 rk_cipher_algs
[i
]->alg
.skcipher
.base
.base
.cra_name
,
215 rk_cipher_algs
[i
]->stat_req
, rk_cipher_algs
[i
]->stat_fb
);
216 seq_printf(seq
, "\tfallback due to length: %lu\n",
217 rk_cipher_algs
[i
]->stat_fb_len
);
218 seq_printf(seq
, "\tfallback due to alignment: %lu\n",
219 rk_cipher_algs
[i
]->stat_fb_align
);
220 seq_printf(seq
, "\tfallback due to SGs: %lu\n",
221 rk_cipher_algs
[i
]->stat_fb_sgdiff
);
223 case CRYPTO_ALG_TYPE_AHASH
:
224 seq_printf(seq
, "%s %s reqs=%lu fallback=%lu\n",
225 rk_cipher_algs
[i
]->alg
.hash
.base
.halg
.base
.cra_driver_name
,
226 rk_cipher_algs
[i
]->alg
.hash
.base
.halg
.base
.cra_name
,
227 rk_cipher_algs
[i
]->stat_req
, rk_cipher_algs
[i
]->stat_fb
);
234 DEFINE_SHOW_ATTRIBUTE(rk_crypto_debugfs
);
236 static void register_debugfs(struct rk_crypto_info
*crypto_info
)
238 struct dentry
*dbgfs_dir __maybe_unused
;
239 struct dentry
*dbgfs_stats __maybe_unused
;
241 /* Ignore error of debugfs */
242 dbgfs_dir
= debugfs_create_dir("rk3288_crypto", NULL
);
243 dbgfs_stats
= debugfs_create_file("stats", 0444, dbgfs_dir
, &rocklist
,
244 &rk_crypto_debugfs_fops
);
246 #ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG
247 rocklist
.dbgfs_dir
= dbgfs_dir
;
248 rocklist
.dbgfs_stats
= dbgfs_stats
;
252 static int rk_crypto_register(struct rk_crypto_info
*crypto_info
)
257 for (i
= 0; i
< ARRAY_SIZE(rk_cipher_algs
); i
++) {
258 rk_cipher_algs
[i
]->dev
= crypto_info
;
259 switch (rk_cipher_algs
[i
]->type
) {
260 case CRYPTO_ALG_TYPE_SKCIPHER
:
261 dev_info(crypto_info
->dev
, "Register %s as %s\n",
262 rk_cipher_algs
[i
]->alg
.skcipher
.base
.base
.cra_name
,
263 rk_cipher_algs
[i
]->alg
.skcipher
.base
.base
.cra_driver_name
);
264 err
= crypto_engine_register_skcipher(&rk_cipher_algs
[i
]->alg
.skcipher
);
266 case CRYPTO_ALG_TYPE_AHASH
:
267 dev_info(crypto_info
->dev
, "Register %s as %s\n",
268 rk_cipher_algs
[i
]->alg
.hash
.base
.halg
.base
.cra_name
,
269 rk_cipher_algs
[i
]->alg
.hash
.base
.halg
.base
.cra_driver_name
);
270 err
= crypto_engine_register_ahash(&rk_cipher_algs
[i
]->alg
.hash
);
273 dev_err(crypto_info
->dev
, "unknown algorithm\n");
276 goto err_cipher_algs
;
281 for (k
= 0; k
< i
; k
++) {
282 if (rk_cipher_algs
[i
]->type
== CRYPTO_ALG_TYPE_SKCIPHER
)
283 crypto_engine_unregister_skcipher(&rk_cipher_algs
[k
]->alg
.skcipher
);
285 crypto_engine_unregister_ahash(&rk_cipher_algs
[i
]->alg
.hash
);
290 static void rk_crypto_unregister(void)
294 for (i
= 0; i
< ARRAY_SIZE(rk_cipher_algs
); i
++) {
295 if (rk_cipher_algs
[i
]->type
== CRYPTO_ALG_TYPE_SKCIPHER
)
296 crypto_engine_unregister_skcipher(&rk_cipher_algs
[i
]->alg
.skcipher
);
298 crypto_engine_unregister_ahash(&rk_cipher_algs
[i
]->alg
.hash
);
302 static const struct of_device_id crypto_of_id_table
[] = {
303 { .compatible
= "rockchip,rk3288-crypto",
304 .data
= &rk3288_variant
,
306 { .compatible
= "rockchip,rk3328-crypto",
307 .data
= &rk3328_variant
,
309 { .compatible
= "rockchip,rk3399-crypto",
310 .data
= &rk3399_variant
,
314 MODULE_DEVICE_TABLE(of
, crypto_of_id_table
);
316 static int rk_crypto_probe(struct platform_device
*pdev
)
318 struct device
*dev
= &pdev
->dev
;
319 struct rk_crypto_info
*crypto_info
, *first
;
322 crypto_info
= devm_kzalloc(&pdev
->dev
,
323 sizeof(*crypto_info
), GFP_KERNEL
);
329 crypto_info
->dev
= &pdev
->dev
;
330 platform_set_drvdata(pdev
, crypto_info
);
332 crypto_info
->variant
= of_device_get_match_data(&pdev
->dev
);
333 if (!crypto_info
->variant
) {
334 dev_err(&pdev
->dev
, "Missing variant\n");
338 crypto_info
->rst
= devm_reset_control_array_get_exclusive(dev
);
339 if (IS_ERR(crypto_info
->rst
)) {
340 err
= PTR_ERR(crypto_info
->rst
);
344 reset_control_assert(crypto_info
->rst
);
345 usleep_range(10, 20);
346 reset_control_deassert(crypto_info
->rst
);
348 crypto_info
->reg
= devm_platform_ioremap_resource(pdev
, 0);
349 if (IS_ERR(crypto_info
->reg
)) {
350 err
= PTR_ERR(crypto_info
->reg
);
354 err
= rk_crypto_get_clks(crypto_info
);
358 crypto_info
->irq
= platform_get_irq(pdev
, 0);
359 if (crypto_info
->irq
< 0) {
360 err
= crypto_info
->irq
;
364 err
= devm_request_irq(&pdev
->dev
, crypto_info
->irq
,
365 rk_crypto_irq_handle
, IRQF_SHARED
,
369 dev_err(&pdev
->dev
, "irq request failed.\n");
373 crypto_info
->engine
= crypto_engine_alloc_init(&pdev
->dev
, true);
374 if (!crypto_info
->engine
) {
379 crypto_engine_start(crypto_info
->engine
);
380 init_completion(&crypto_info
->complete
);
382 err
= rk_crypto_pm_init(crypto_info
);
386 spin_lock(&rocklist
.lock
);
387 first
= list_first_entry_or_null(&rocklist
.dev_list
,
388 struct rk_crypto_info
, list
);
389 list_add_tail(&crypto_info
->list
, &rocklist
.dev_list
);
390 spin_unlock(&rocklist
.lock
);
393 err
= rk_crypto_register(crypto_info
);
395 dev_err(dev
, "Fail to register crypto algorithms");
396 goto err_register_alg
;
399 register_debugfs(crypto_info
);
405 rk_crypto_pm_exit(crypto_info
);
407 crypto_engine_exit(crypto_info
->engine
);
409 dev_err(dev
, "Crypto Accelerator not successfully registered\n");
413 static void rk_crypto_remove(struct platform_device
*pdev
)
415 struct rk_crypto_info
*crypto_tmp
= platform_get_drvdata(pdev
);
416 struct rk_crypto_info
*first
;
418 spin_lock_bh(&rocklist
.lock
);
419 list_del(&crypto_tmp
->list
);
420 first
= list_first_entry_or_null(&rocklist
.dev_list
,
421 struct rk_crypto_info
, list
);
422 spin_unlock_bh(&rocklist
.lock
);
425 #ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG
426 debugfs_remove_recursive(rocklist
.dbgfs_dir
);
428 rk_crypto_unregister();
430 rk_crypto_pm_exit(crypto_tmp
);
431 crypto_engine_exit(crypto_tmp
->engine
);
434 static struct platform_driver crypto_driver
= {
435 .probe
= rk_crypto_probe
,
436 .remove_new
= rk_crypto_remove
,
438 .name
= "rk3288-crypto",
439 .pm
= &rk_crypto_pm_ops
,
440 .of_match_table
= crypto_of_id_table
,
444 module_platform_driver(crypto_driver
);
446 MODULE_AUTHOR("Zain Wang <zain.wang@rock-chips.com>");
447 MODULE_DESCRIPTION("Support for Rockchip's cryptographic engine");
448 MODULE_LICENSE("GPL");