1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * sun8i-ce-core.c - hardware cryptographic offloader for 4 * Allwinner H3/A64/H5/H2+/H6/R40 SoC 5 * 6 * Copyright (C) 2015-2019 Corentin Labbe <clabbe.montjoie@gmail.com> 7 * 8 * Core file which registers crypto algorithms supported by the CryptoEngine. 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-ce.h" 28 29 /* 30 * mod clock is lower on H3 than other SoC due to some DMA timeout occurring 31 * with high value. 32 * If you want to tune mod clock, loading driver and passing selftest is 33 * insufficient, you need to test with some LUKS test (mount and write to it) 34 */ 35 static const struct ce_variant ce_h3_variant = { 36 .alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES, 37 }, 38 .op_mode = { CE_OP_ECB, CE_OP_CBC 39 }, 40 .ce_clks = { 41 { "bus", 0, 200000000 }, 42 { "mod", 50000000, 0 }, 43 } 44 }; 45 46 static const struct ce_variant ce_h5_variant = { 47 .alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES, 48 }, 49 .op_mode = { CE_OP_ECB, CE_OP_CBC 50 }, 51 .ce_clks = { 52 { "bus", 0, 200000000 }, 53 { "mod", 300000000, 0 }, 54 } 55 }; 56 57 static const struct ce_variant ce_h6_variant = { 58 .alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES, 59 }, 60 .op_mode = { CE_OP_ECB, CE_OP_CBC 61 }, 62 .has_t_dlen_in_bytes = true, 63 .ce_clks = { 64 { "bus", 0, 200000000 }, 65 { "mod", 300000000, 0 }, 66 { "ram", 0, 400000000 }, 67 } 68 }; 69 70 static const struct ce_variant ce_a64_variant = { 71 .alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES, 72 }, 73 .op_mode = { CE_OP_ECB, CE_OP_CBC 74 }, 75 .ce_clks = { 76 { "bus", 0, 200000000 }, 77 { "mod", 300000000, 0 }, 78 } 79 }; 80 81 static const struct ce_variant ce_r40_variant = { 82 .alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES, 83 }, 84 .op_mode = { CE_OP_ECB, CE_OP_CBC 85 }, 86 .ce_clks = { 87 { "bus", 0, 200000000 }, 88 { "mod", 300000000, 0 }, 89 } 90 }; 91 92 /* 93 * sun8i_ce_get_engine_number() get the next channel slot 94 * This is a simple round-robin way of getting the next channel 95 */ 96 int sun8i_ce_get_engine_number(struct sun8i_ce_dev *ce) 97 { 98 return atomic_inc_return(&ce->flow) % MAXFLOW; 99 } 100 101 int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name) 102 { 103 u32 v; 104 int err = 0; 105 106 #ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG 107 ce->chanlist[flow].stat_req++; 108 #endif 109 110 mutex_lock(&ce->mlock); 111 112 v = readl(ce->base + CE_ICR); 113 v |= 1 << flow; 114 writel(v, ce->base + CE_ICR); 115 116 reinit_completion(&ce->chanlist[flow].complete); 117 writel(ce->chanlist[flow].t_phy, ce->base + CE_TDQ); 118 119 ce->chanlist[flow].status = 0; 120 /* Be sure all data is written before enabling the task */ 121 wmb(); 122 123 v = 1 | (ce->chanlist[flow].tl->t_common_ctl & 0x7F) << 8; 124 writel(v, ce->base + CE_TLR); 125 mutex_unlock(&ce->mlock); 126 127 wait_for_completion_interruptible_timeout(&ce->chanlist[flow].complete, 128 msecs_to_jiffies(ce->chanlist[flow].timeout)); 129 130 if (ce->chanlist[flow].status == 0) { 131 dev_err(ce->dev, "DMA timeout for %s\n", name); 132 err = -EFAULT; 133 } 134 /* No need to lock for this read, the channel is locked so 135 * nothing could modify the error value for this channel 136 */ 137 v = readl(ce->base + CE_ESR); 138 if (v) { 139 v >>= (flow * 4); 140 v &= 0xFF; 141 if (v) { 142 dev_err(ce->dev, "CE ERROR: %x for flow %x\n", v, flow); 143 err = -EFAULT; 144 } 145 if (v & CE_ERR_ALGO_NOTSUP) 146 dev_err(ce->dev, "CE ERROR: algorithm not supported\n"); 147 if (v & CE_ERR_DATALEN) 148 dev_err(ce->dev, "CE ERROR: data length error\n"); 149 if (v & CE_ERR_KEYSRAM) 150 dev_err(ce->dev, "CE ERROR: keysram access error for AES\n"); 151 if (v & CE_ERR_ADDR_INVALID) 152 dev_err(ce->dev, "CE ERROR: address invalid\n"); 153 } 154 155 return err; 156 } 157 158 static irqreturn_t ce_irq_handler(int irq, void *data) 159 { 160 struct sun8i_ce_dev *ce = (struct sun8i_ce_dev *)data; 161 int flow = 0; 162 u32 p; 163 164 p = readl(ce->base + CE_ISR); 165 for (flow = 0; flow < MAXFLOW; flow++) { 166 if (p & (BIT(flow))) { 167 writel(BIT(flow), ce->base + CE_ISR); 168 ce->chanlist[flow].status = 1; 169 complete(&ce->chanlist[flow].complete); 170 } 171 } 172 173 return IRQ_HANDLED; 174 } 175 176 static struct sun8i_ce_alg_template ce_algs[] = { 177 { 178 .type = CRYPTO_ALG_TYPE_SKCIPHER, 179 .ce_algo_id = CE_ID_CIPHER_AES, 180 .ce_blockmode = CE_ID_OP_CBC, 181 .alg.skcipher = { 182 .base = { 183 .cra_name = "cbc(aes)", 184 .cra_driver_name = "cbc-aes-sun8i-ce", 185 .cra_priority = 400, 186 .cra_blocksize = AES_BLOCK_SIZE, 187 .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | 188 CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, 189 .cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx), 190 .cra_module = THIS_MODULE, 191 .cra_alignmask = 0xf, 192 .cra_init = sun8i_ce_cipher_init, 193 .cra_exit = sun8i_ce_cipher_exit, 194 }, 195 .min_keysize = AES_MIN_KEY_SIZE, 196 .max_keysize = AES_MAX_KEY_SIZE, 197 .ivsize = AES_BLOCK_SIZE, 198 .setkey = sun8i_ce_aes_setkey, 199 .encrypt = sun8i_ce_skencrypt, 200 .decrypt = sun8i_ce_skdecrypt, 201 } 202 }, 203 { 204 .type = CRYPTO_ALG_TYPE_SKCIPHER, 205 .ce_algo_id = CE_ID_CIPHER_AES, 206 .ce_blockmode = CE_ID_OP_ECB, 207 .alg.skcipher = { 208 .base = { 209 .cra_name = "ecb(aes)", 210 .cra_driver_name = "ecb-aes-sun8i-ce", 211 .cra_priority = 400, 212 .cra_blocksize = AES_BLOCK_SIZE, 213 .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | 214 CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, 215 .cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx), 216 .cra_module = THIS_MODULE, 217 .cra_alignmask = 0xf, 218 .cra_init = sun8i_ce_cipher_init, 219 .cra_exit = sun8i_ce_cipher_exit, 220 }, 221 .min_keysize = AES_MIN_KEY_SIZE, 222 .max_keysize = AES_MAX_KEY_SIZE, 223 .setkey = sun8i_ce_aes_setkey, 224 .encrypt = sun8i_ce_skencrypt, 225 .decrypt = sun8i_ce_skdecrypt, 226 } 227 }, 228 { 229 .type = CRYPTO_ALG_TYPE_SKCIPHER, 230 .ce_algo_id = CE_ID_CIPHER_DES3, 231 .ce_blockmode = CE_ID_OP_CBC, 232 .alg.skcipher = { 233 .base = { 234 .cra_name = "cbc(des3_ede)", 235 .cra_driver_name = "cbc-des3-sun8i-ce", 236 .cra_priority = 400, 237 .cra_blocksize = DES3_EDE_BLOCK_SIZE, 238 .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | 239 CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, 240 .cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx), 241 .cra_module = THIS_MODULE, 242 .cra_alignmask = 0xf, 243 .cra_init = sun8i_ce_cipher_init, 244 .cra_exit = sun8i_ce_cipher_exit, 245 }, 246 .min_keysize = DES3_EDE_KEY_SIZE, 247 .max_keysize = DES3_EDE_KEY_SIZE, 248 .ivsize = DES3_EDE_BLOCK_SIZE, 249 .setkey = sun8i_ce_des3_setkey, 250 .encrypt = sun8i_ce_skencrypt, 251 .decrypt = sun8i_ce_skdecrypt, 252 } 253 }, 254 { 255 .type = CRYPTO_ALG_TYPE_SKCIPHER, 256 .ce_algo_id = CE_ID_CIPHER_DES3, 257 .ce_blockmode = CE_ID_OP_ECB, 258 .alg.skcipher = { 259 .base = { 260 .cra_name = "ecb(des3_ede)", 261 .cra_driver_name = "ecb-des3-sun8i-ce", 262 .cra_priority = 400, 263 .cra_blocksize = DES3_EDE_BLOCK_SIZE, 264 .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | 265 CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, 266 .cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx), 267 .cra_module = THIS_MODULE, 268 .cra_alignmask = 0xf, 269 .cra_init = sun8i_ce_cipher_init, 270 .cra_exit = sun8i_ce_cipher_exit, 271 }, 272 .min_keysize = DES3_EDE_KEY_SIZE, 273 .max_keysize = DES3_EDE_KEY_SIZE, 274 .setkey = sun8i_ce_des3_setkey, 275 .encrypt = sun8i_ce_skencrypt, 276 .decrypt = sun8i_ce_skdecrypt, 277 } 278 }, 279 }; 280 281 #ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG 282 static int sun8i_ce_dbgfs_read(struct seq_file *seq, void *v) 283 { 284 struct sun8i_ce_dev *ce = seq->private; 285 int i; 286 287 for (i = 0; i < MAXFLOW; i++) 288 seq_printf(seq, "Channel %d: nreq %lu\n", i, ce->chanlist[i].stat_req); 289 290 for (i = 0; i < ARRAY_SIZE(ce_algs); i++) { 291 if (!ce_algs[i].ce) 292 continue; 293 switch (ce_algs[i].type) { 294 case CRYPTO_ALG_TYPE_SKCIPHER: 295 seq_printf(seq, "%s %s %lu %lu\n", 296 ce_algs[i].alg.skcipher.base.cra_driver_name, 297 ce_algs[i].alg.skcipher.base.cra_name, 298 ce_algs[i].stat_req, ce_algs[i].stat_fb); 299 break; 300 } 301 } 302 return 0; 303 } 304 305 static int sun8i_ce_dbgfs_open(struct inode *inode, struct file *file) 306 { 307 return single_open(file, sun8i_ce_dbgfs_read, inode->i_private); 308 } 309 310 static const struct file_operations sun8i_ce_debugfs_fops = { 311 .owner = THIS_MODULE, 312 .open = sun8i_ce_dbgfs_open, 313 .read = seq_read, 314 .llseek = seq_lseek, 315 .release = single_release, 316 }; 317 #endif 318 319 static void sun8i_ce_free_chanlist(struct sun8i_ce_dev *ce, int i) 320 { 321 while (i >= 0) { 322 crypto_engine_exit(ce->chanlist[i].engine); 323 if (ce->chanlist[i].tl) 324 dma_free_coherent(ce->dev, sizeof(struct ce_task), 325 ce->chanlist[i].tl, 326 ce->chanlist[i].t_phy); 327 i--; 328 } 329 } 330 331 /* 332 * Allocate the channel list structure 333 */ 334 static int sun8i_ce_allocate_chanlist(struct sun8i_ce_dev *ce) 335 { 336 int i, err; 337 338 ce->chanlist = devm_kcalloc(ce->dev, MAXFLOW, 339 sizeof(struct sun8i_ce_flow), GFP_KERNEL); 340 if (!ce->chanlist) 341 return -ENOMEM; 342 343 for (i = 0; i < MAXFLOW; i++) { 344 init_completion(&ce->chanlist[i].complete); 345 346 ce->chanlist[i].engine = crypto_engine_alloc_init(ce->dev, true); 347 if (!ce->chanlist[i].engine) { 348 dev_err(ce->dev, "Cannot allocate engine\n"); 349 i--; 350 err = -ENOMEM; 351 goto error_engine; 352 } 353 err = crypto_engine_start(ce->chanlist[i].engine); 354 if (err) { 355 dev_err(ce->dev, "Cannot start engine\n"); 356 goto error_engine; 357 } 358 ce->chanlist[i].tl = dma_alloc_coherent(ce->dev, 359 sizeof(struct ce_task), 360 &ce->chanlist[i].t_phy, 361 GFP_KERNEL); 362 if (!ce->chanlist[i].tl) { 363 dev_err(ce->dev, "Cannot get DMA memory for task %d\n", 364 i); 365 err = -ENOMEM; 366 goto error_engine; 367 } 368 } 369 return 0; 370 error_engine: 371 sun8i_ce_free_chanlist(ce, i); 372 return err; 373 } 374 375 /* 376 * Power management strategy: The device is suspended unless a TFM exists for 377 * one of the algorithms proposed by this driver. 378 */ 379 static int sun8i_ce_pm_suspend(struct device *dev) 380 { 381 struct sun8i_ce_dev *ce = dev_get_drvdata(dev); 382 int i; 383 384 reset_control_assert(ce->reset); 385 for (i = 0; i < CE_MAX_CLOCKS; i++) 386 clk_disable_unprepare(ce->ceclks[i]); 387 return 0; 388 } 389 390 static int sun8i_ce_pm_resume(struct device *dev) 391 { 392 struct sun8i_ce_dev *ce = dev_get_drvdata(dev); 393 int err, i; 394 395 for (i = 0; i < CE_MAX_CLOCKS; i++) { 396 if (!ce->variant->ce_clks[i].name) 397 continue; 398 err = clk_prepare_enable(ce->ceclks[i]); 399 if (err) { 400 dev_err(ce->dev, "Cannot prepare_enable %s\n", 401 ce->variant->ce_clks[i].name); 402 goto error; 403 } 404 } 405 err = reset_control_deassert(ce->reset); 406 if (err) { 407 dev_err(ce->dev, "Cannot deassert reset control\n"); 408 goto error; 409 } 410 return 0; 411 error: 412 sun8i_ce_pm_suspend(dev); 413 return err; 414 } 415 416 static const struct dev_pm_ops sun8i_ce_pm_ops = { 417 SET_RUNTIME_PM_OPS(sun8i_ce_pm_suspend, sun8i_ce_pm_resume, NULL) 418 }; 419 420 static int sun8i_ce_pm_init(struct sun8i_ce_dev *ce) 421 { 422 int err; 423 424 pm_runtime_use_autosuspend(ce->dev); 425 pm_runtime_set_autosuspend_delay(ce->dev, 2000); 426 427 err = pm_runtime_set_suspended(ce->dev); 428 if (err) 429 return err; 430 pm_runtime_enable(ce->dev); 431 return err; 432 } 433 434 static void sun8i_ce_pm_exit(struct sun8i_ce_dev *ce) 435 { 436 pm_runtime_disable(ce->dev); 437 } 438 439 static int sun8i_ce_get_clks(struct sun8i_ce_dev *ce) 440 { 441 unsigned long cr; 442 int err, i; 443 444 for (i = 0; i < CE_MAX_CLOCKS; i++) { 445 if (!ce->variant->ce_clks[i].name) 446 continue; 447 ce->ceclks[i] = devm_clk_get(ce->dev, ce->variant->ce_clks[i].name); 448 if (IS_ERR(ce->ceclks[i])) { 449 err = PTR_ERR(ce->ceclks[i]); 450 dev_err(ce->dev, "Cannot get %s CE clock err=%d\n", 451 ce->variant->ce_clks[i].name, err); 452 return err; 453 } 454 cr = clk_get_rate(ce->ceclks[i]); 455 if (!cr) 456 return -EINVAL; 457 if (ce->variant->ce_clks[i].freq > 0 && 458 cr != ce->variant->ce_clks[i].freq) { 459 dev_info(ce->dev, "Set %s clock to %lu (%lu Mhz) from %lu (%lu Mhz)\n", 460 ce->variant->ce_clks[i].name, 461 ce->variant->ce_clks[i].freq, 462 ce->variant->ce_clks[i].freq / 1000000, 463 cr, cr / 1000000); 464 err = clk_set_rate(ce->ceclks[i], ce->variant->ce_clks[i].freq); 465 if (err) 466 dev_err(ce->dev, "Fail to set %s clk speed to %lu hz\n", 467 ce->variant->ce_clks[i].name, 468 ce->variant->ce_clks[i].freq); 469 } 470 if (ce->variant->ce_clks[i].max_freq > 0 && 471 cr > ce->variant->ce_clks[i].max_freq) 472 dev_warn(ce->dev, "Frequency for %s (%lu hz) is higher than datasheet's recommendation (%lu hz)", 473 ce->variant->ce_clks[i].name, cr, 474 ce->variant->ce_clks[i].max_freq); 475 } 476 return 0; 477 } 478 479 static int sun8i_ce_register_algs(struct sun8i_ce_dev *ce) 480 { 481 int ce_method, err, id, i; 482 483 for (i = 0; i < ARRAY_SIZE(ce_algs); i++) { 484 ce_algs[i].ce = ce; 485 switch (ce_algs[i].type) { 486 case CRYPTO_ALG_TYPE_SKCIPHER: 487 id = ce_algs[i].ce_algo_id; 488 ce_method = ce->variant->alg_cipher[id]; 489 if (ce_method == CE_ID_NOTSUPP) { 490 dev_dbg(ce->dev, 491 "DEBUG: Algo of %s not supported\n", 492 ce_algs[i].alg.skcipher.base.cra_name); 493 ce_algs[i].ce = NULL; 494 break; 495 } 496 id = ce_algs[i].ce_blockmode; 497 ce_method = ce->variant->op_mode[id]; 498 if (ce_method == CE_ID_NOTSUPP) { 499 dev_dbg(ce->dev, "DEBUG: Blockmode of %s not supported\n", 500 ce_algs[i].alg.skcipher.base.cra_name); 501 ce_algs[i].ce = NULL; 502 break; 503 } 504 dev_info(ce->dev, "Register %s\n", 505 ce_algs[i].alg.skcipher.base.cra_name); 506 err = crypto_register_skcipher(&ce_algs[i].alg.skcipher); 507 if (err) { 508 dev_err(ce->dev, "ERROR: Fail to register %s\n", 509 ce_algs[i].alg.skcipher.base.cra_name); 510 ce_algs[i].ce = NULL; 511 return err; 512 } 513 break; 514 default: 515 ce_algs[i].ce = NULL; 516 dev_err(ce->dev, "ERROR: tried to register an unknown algo\n"); 517 } 518 } 519 return 0; 520 } 521 522 static void sun8i_ce_unregister_algs(struct sun8i_ce_dev *ce) 523 { 524 int i; 525 526 for (i = 0; i < ARRAY_SIZE(ce_algs); i++) { 527 if (!ce_algs[i].ce) 528 continue; 529 switch (ce_algs[i].type) { 530 case CRYPTO_ALG_TYPE_SKCIPHER: 531 dev_info(ce->dev, "Unregister %d %s\n", i, 532 ce_algs[i].alg.skcipher.base.cra_name); 533 crypto_unregister_skcipher(&ce_algs[i].alg.skcipher); 534 break; 535 } 536 } 537 } 538 539 static int sun8i_ce_probe(struct platform_device *pdev) 540 { 541 struct sun8i_ce_dev *ce; 542 int err, irq; 543 u32 v; 544 545 ce = devm_kzalloc(&pdev->dev, sizeof(*ce), GFP_KERNEL); 546 if (!ce) 547 return -ENOMEM; 548 549 ce->dev = &pdev->dev; 550 platform_set_drvdata(pdev, ce); 551 552 ce->variant = of_device_get_match_data(&pdev->dev); 553 if (!ce->variant) { 554 dev_err(&pdev->dev, "Missing Crypto Engine variant\n"); 555 return -EINVAL; 556 } 557 558 ce->base = devm_platform_ioremap_resource(pdev, 0); 559 if (IS_ERR(ce->base)) 560 return PTR_ERR(ce->base); 561 562 err = sun8i_ce_get_clks(ce); 563 if (err) 564 return err; 565 566 /* Get Non Secure IRQ */ 567 irq = platform_get_irq(pdev, 0); 568 if (irq < 0) 569 return irq; 570 571 ce->reset = devm_reset_control_get(&pdev->dev, NULL); 572 if (IS_ERR(ce->reset)) { 573 if (PTR_ERR(ce->reset) == -EPROBE_DEFER) 574 return PTR_ERR(ce->reset); 575 dev_err(&pdev->dev, "No reset control found\n"); 576 return PTR_ERR(ce->reset); 577 } 578 579 mutex_init(&ce->mlock); 580 581 err = sun8i_ce_allocate_chanlist(ce); 582 if (err) 583 return err; 584 585 err = sun8i_ce_pm_init(ce); 586 if (err) 587 goto error_pm; 588 589 err = devm_request_irq(&pdev->dev, irq, ce_irq_handler, 0, 590 "sun8i-ce-ns", ce); 591 if (err) { 592 dev_err(ce->dev, "Cannot request CryptoEngine Non-secure IRQ (err=%d)\n", err); 593 goto error_irq; 594 } 595 596 err = sun8i_ce_register_algs(ce); 597 if (err) 598 goto error_alg; 599 600 err = pm_runtime_get_sync(ce->dev); 601 if (err < 0) 602 goto error_alg; 603 604 v = readl(ce->base + CE_CTR); 605 v >>= CE_DIE_ID_SHIFT; 606 v &= CE_DIE_ID_MASK; 607 dev_info(&pdev->dev, "CryptoEngine Die ID %x\n", v); 608 609 pm_runtime_put_sync(ce->dev); 610 611 #ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG 612 /* Ignore error of debugfs */ 613 ce->dbgfs_dir = debugfs_create_dir("sun8i-ce", NULL); 614 ce->dbgfs_stats = debugfs_create_file("stats", 0444, 615 ce->dbgfs_dir, ce, 616 &sun8i_ce_debugfs_fops); 617 #endif 618 619 return 0; 620 error_alg: 621 sun8i_ce_unregister_algs(ce); 622 error_irq: 623 sun8i_ce_pm_exit(ce); 624 error_pm: 625 sun8i_ce_free_chanlist(ce, MAXFLOW - 1); 626 return err; 627 } 628 629 static int sun8i_ce_remove(struct platform_device *pdev) 630 { 631 struct sun8i_ce_dev *ce = platform_get_drvdata(pdev); 632 633 sun8i_ce_unregister_algs(ce); 634 635 #ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG 636 debugfs_remove_recursive(ce->dbgfs_dir); 637 #endif 638 639 sun8i_ce_free_chanlist(ce, MAXFLOW - 1); 640 641 sun8i_ce_pm_exit(ce); 642 return 0; 643 } 644 645 static const struct of_device_id sun8i_ce_crypto_of_match_table[] = { 646 { .compatible = "allwinner,sun8i-h3-crypto", 647 .data = &ce_h3_variant }, 648 { .compatible = "allwinner,sun8i-r40-crypto", 649 .data = &ce_r40_variant }, 650 { .compatible = "allwinner,sun50i-a64-crypto", 651 .data = &ce_a64_variant }, 652 { .compatible = "allwinner,sun50i-h5-crypto", 653 .data = &ce_h5_variant }, 654 { .compatible = "allwinner,sun50i-h6-crypto", 655 .data = &ce_h6_variant }, 656 {} 657 }; 658 MODULE_DEVICE_TABLE(of, sun8i_ce_crypto_of_match_table); 659 660 static struct platform_driver sun8i_ce_driver = { 661 .probe = sun8i_ce_probe, 662 .remove = sun8i_ce_remove, 663 .driver = { 664 .name = "sun8i-ce", 665 .pm = &sun8i_ce_pm_ops, 666 .of_match_table = sun8i_ce_crypto_of_match_table, 667 }, 668 }; 669 670 module_platform_driver(sun8i_ce_driver); 671 672 MODULE_DESCRIPTION("Allwinner Crypto Engine cryptographic offloader"); 673 MODULE_LICENSE("GPL"); 674 MODULE_AUTHOR("Corentin Labbe <clabbe.montjoie@gmail.com>"); 675