.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2015, Linaro Limited |
---|
3 | | - * |
---|
4 | | - * This software is licensed under the terms of the GNU General Public |
---|
5 | | - * License version 2, as published by the Free Software Foundation, and |
---|
6 | | - * may be copied, distributed, and modified under those terms. |
---|
7 | | - * |
---|
8 | | - * This program is distributed in the hope that it will be useful, |
---|
9 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
10 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
11 | | - * GNU General Public License for more details. |
---|
12 | | - * |
---|
13 | 4 | */ |
---|
14 | 5 | |
---|
15 | 6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
---|
16 | 7 | |
---|
17 | 8 | #include <linux/arm-smccc.h> |
---|
| 9 | +#include <linux/crash_dump.h> |
---|
18 | 10 | #include <linux/errno.h> |
---|
19 | 11 | #include <linux/io.h> |
---|
20 | 12 | #include <linux/module.h> |
---|
.. | .. |
---|
26 | 18 | #include <linux/tee_drv.h> |
---|
27 | 19 | #include <linux/types.h> |
---|
28 | 20 | #include <linux/uaccess.h> |
---|
| 21 | +#include <linux/workqueue.h> |
---|
29 | 22 | #include "optee_private.h" |
---|
30 | 23 | #include "optee_smc.h" |
---|
31 | 24 | #include "shm_pool.h" |
---|
.. | .. |
---|
214 | 207 | |
---|
215 | 208 | if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) |
---|
216 | 209 | v.gen_caps |= TEE_GEN_CAP_REG_MEM; |
---|
| 210 | + if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL) |
---|
| 211 | + v.gen_caps |= TEE_GEN_CAP_MEMREF_NULL; |
---|
217 | 212 | *vers = v; |
---|
| 213 | +} |
---|
| 214 | + |
---|
| 215 | +static void optee_bus_scan(struct work_struct *work) |
---|
| 216 | +{ |
---|
| 217 | + WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP)); |
---|
218 | 218 | } |
---|
219 | 219 | |
---|
220 | 220 | static int optee_open(struct tee_context *ctx) |
---|
.. | .. |
---|
240 | 240 | kfree(ctxdata); |
---|
241 | 241 | return -EBUSY; |
---|
242 | 242 | } |
---|
243 | | - } |
---|
244 | 243 | |
---|
| 244 | + if (!optee->scan_bus_done) { |
---|
| 245 | + INIT_WORK(&optee->scan_bus_work, optee_bus_scan); |
---|
| 246 | + optee->scan_bus_wq = create_workqueue("optee_bus_scan"); |
---|
| 247 | + if (!optee->scan_bus_wq) { |
---|
| 248 | + kfree(ctxdata); |
---|
| 249 | + return -ECHILD; |
---|
| 250 | + } |
---|
| 251 | + queue_work(optee->scan_bus_wq, &optee->scan_bus_work); |
---|
| 252 | + optee->scan_bus_done = true; |
---|
| 253 | + } |
---|
| 254 | + } |
---|
245 | 255 | mutex_init(&ctxdata->mutex); |
---|
246 | 256 | INIT_LIST_HEAD(&ctxdata->sess_list); |
---|
| 257 | + |
---|
| 258 | + if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL) |
---|
| 259 | + ctx->cap_memref_null = true; |
---|
| 260 | + else |
---|
| 261 | + ctx->cap_memref_null = false; |
---|
247 | 262 | |
---|
248 | 263 | ctx->data = ctxdata; |
---|
249 | 264 | return 0; |
---|
.. | .. |
---|
263 | 278 | if (!ctxdata) |
---|
264 | 279 | return; |
---|
265 | 280 | |
---|
266 | | - shm = tee_shm_alloc(ctx, sizeof(struct optee_msg_arg), TEE_SHM_MAPPED); |
---|
| 281 | + shm = tee_shm_alloc(ctx, sizeof(struct optee_msg_arg), |
---|
| 282 | + TEE_SHM_MAPPED | TEE_SHM_PRIV); |
---|
267 | 283 | if (!IS_ERR(shm)) { |
---|
268 | 284 | arg = tee_shm_get_va(shm, 0); |
---|
269 | 285 | /* |
---|
.. | .. |
---|
295 | 311 | |
---|
296 | 312 | ctx->data = NULL; |
---|
297 | 313 | |
---|
298 | | - if (teedev == optee->supp_teedev) |
---|
| 314 | + if (teedev == optee->supp_teedev) { |
---|
| 315 | + if (optee->scan_bus_wq) { |
---|
| 316 | + destroy_workqueue(optee->scan_bus_wq); |
---|
| 317 | + optee->scan_bus_wq = NULL; |
---|
| 318 | + } |
---|
299 | 319 | optee_supp_release(&optee->supp); |
---|
| 320 | + } |
---|
300 | 321 | } |
---|
301 | 322 | |
---|
302 | 323 | static const struct tee_driver_ops optee_ops = { |
---|
.. | .. |
---|
409 | 430 | return true; |
---|
410 | 431 | } |
---|
411 | 432 | |
---|
| 433 | +static struct tee_shm_pool *optee_config_dyn_shm(void) |
---|
| 434 | +{ |
---|
| 435 | + struct tee_shm_pool_mgr *priv_mgr; |
---|
| 436 | + struct tee_shm_pool_mgr *dmabuf_mgr; |
---|
| 437 | + void *rc; |
---|
| 438 | + |
---|
| 439 | + rc = optee_shm_pool_alloc_pages(); |
---|
| 440 | + if (IS_ERR(rc)) |
---|
| 441 | + return rc; |
---|
| 442 | + priv_mgr = rc; |
---|
| 443 | + |
---|
| 444 | + rc = optee_shm_pool_alloc_pages(); |
---|
| 445 | + if (IS_ERR(rc)) { |
---|
| 446 | + tee_shm_pool_mgr_destroy(priv_mgr); |
---|
| 447 | + return rc; |
---|
| 448 | + } |
---|
| 449 | + dmabuf_mgr = rc; |
---|
| 450 | + |
---|
| 451 | + rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr); |
---|
| 452 | + if (IS_ERR(rc)) { |
---|
| 453 | + tee_shm_pool_mgr_destroy(priv_mgr); |
---|
| 454 | + tee_shm_pool_mgr_destroy(dmabuf_mgr); |
---|
| 455 | + } |
---|
| 456 | + |
---|
| 457 | + return rc; |
---|
| 458 | +} |
---|
| 459 | + |
---|
412 | 460 | static struct tee_shm_pool * |
---|
413 | | -optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm, |
---|
414 | | - u32 sec_caps) |
---|
| 461 | +optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm) |
---|
415 | 462 | { |
---|
416 | 463 | union { |
---|
417 | 464 | struct arm_smccc_res smccc; |
---|
.. | .. |
---|
426 | 473 | struct tee_shm_pool_mgr *priv_mgr; |
---|
427 | 474 | struct tee_shm_pool_mgr *dmabuf_mgr; |
---|
428 | 475 | void *rc; |
---|
| 476 | + const int sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; |
---|
429 | 477 | |
---|
430 | 478 | invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc); |
---|
431 | 479 | if (res.result.status != OPTEE_SMC_RETURN_OK) { |
---|
432 | | - pr_info("shm service not available\n"); |
---|
| 480 | + pr_err("static shm service not available\n"); |
---|
433 | 481 | return ERR_PTR(-ENOENT); |
---|
434 | 482 | } |
---|
435 | 483 | |
---|
.. | .. |
---|
455 | 503 | } |
---|
456 | 504 | vaddr = (unsigned long)va; |
---|
457 | 505 | |
---|
458 | | - /* |
---|
459 | | - * If OP-TEE can work with unregistered SHM, we will use own pool |
---|
460 | | - * for private shm |
---|
461 | | - */ |
---|
462 | | - if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) { |
---|
463 | | - rc = optee_shm_pool_alloc_pages(); |
---|
464 | | - if (IS_ERR(rc)) |
---|
465 | | - goto err_memunmap; |
---|
466 | | - priv_mgr = rc; |
---|
467 | | - } else { |
---|
468 | | - const size_t sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; |
---|
| 506 | + rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz, |
---|
| 507 | + 3 /* 8 bytes aligned */); |
---|
| 508 | + if (IS_ERR(rc)) |
---|
| 509 | + goto err_memunmap; |
---|
| 510 | + priv_mgr = rc; |
---|
469 | 511 | |
---|
470 | | - rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz, |
---|
471 | | - 3 /* 8 bytes aligned */); |
---|
472 | | - if (IS_ERR(rc)) |
---|
473 | | - goto err_memunmap; |
---|
474 | | - priv_mgr = rc; |
---|
475 | | - |
---|
476 | | - vaddr += sz; |
---|
477 | | - paddr += sz; |
---|
478 | | - size -= sz; |
---|
479 | | - } |
---|
| 512 | + vaddr += sz; |
---|
| 513 | + paddr += sz; |
---|
| 514 | + size -= sz; |
---|
480 | 515 | |
---|
481 | 516 | rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, size, PAGE_SHIFT); |
---|
482 | 517 | if (IS_ERR(rc)) |
---|
.. | .. |
---|
519 | 554 | arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res); |
---|
520 | 555 | } |
---|
521 | 556 | |
---|
522 | | -static optee_invoke_fn *get_invoke_func(struct device_node *np) |
---|
| 557 | +static optee_invoke_fn *get_invoke_func(struct device *dev) |
---|
523 | 558 | { |
---|
524 | 559 | const char *method; |
---|
525 | 560 | |
---|
526 | | - pr_info("probing for conduit method from DT.\n"); |
---|
| 561 | + pr_info("probing for conduit method.\n"); |
---|
527 | 562 | |
---|
528 | | - if (of_property_read_string(np, "method", &method)) { |
---|
| 563 | + if (device_property_read_string(dev, "method", &method)) { |
---|
529 | 564 | pr_warn("missing \"method\" property\n"); |
---|
530 | 565 | return ERR_PTR(-ENXIO); |
---|
531 | 566 | } |
---|
.. | .. |
---|
539 | 574 | return ERR_PTR(-EINVAL); |
---|
540 | 575 | } |
---|
541 | 576 | |
---|
542 | | -static struct optee *optee_probe(struct device_node *np) |
---|
| 577 | +/* optee_remove - Device Removal Routine |
---|
| 578 | + * @pdev: platform device information struct |
---|
| 579 | + * |
---|
| 580 | + * optee_remove is called by platform subsystem to alert the driver |
---|
| 581 | + * that it should release the device |
---|
| 582 | + */ |
---|
| 583 | + |
---|
| 584 | +static int optee_remove(struct platform_device *pdev) |
---|
| 585 | +{ |
---|
| 586 | + struct optee *optee = platform_get_drvdata(pdev); |
---|
| 587 | + |
---|
| 588 | + /* Unregister OP-TEE specific client devices on TEE bus */ |
---|
| 589 | + optee_unregister_devices(); |
---|
| 590 | + |
---|
| 591 | + teedev_close_context(optee->ctx); |
---|
| 592 | + /* |
---|
| 593 | + * Ask OP-TEE to free all cached shared memory objects to decrease |
---|
| 594 | + * reference counters and also avoid wild pointers in secure world |
---|
| 595 | + * into the old shared memory range. |
---|
| 596 | + */ |
---|
| 597 | + optee_disable_shm_cache(optee); |
---|
| 598 | + |
---|
| 599 | + /* |
---|
| 600 | + * The two devices have to be unregistered before we can free the |
---|
| 601 | + * other resources. |
---|
| 602 | + */ |
---|
| 603 | + tee_device_unregister(optee->supp_teedev); |
---|
| 604 | + tee_device_unregister(optee->teedev); |
---|
| 605 | + |
---|
| 606 | + tee_shm_pool_free(optee->pool); |
---|
| 607 | + if (optee->memremaped_shm) |
---|
| 608 | + memunmap(optee->memremaped_shm); |
---|
| 609 | + optee_wait_queue_exit(&optee->wait_queue); |
---|
| 610 | + optee_supp_uninit(&optee->supp); |
---|
| 611 | + mutex_destroy(&optee->call_queue.mutex); |
---|
| 612 | + |
---|
| 613 | + kfree(optee); |
---|
| 614 | + |
---|
| 615 | + return 0; |
---|
| 616 | +} |
---|
| 617 | + |
---|
| 618 | +/* optee_shutdown - Device Removal Routine |
---|
| 619 | + * @pdev: platform device information struct |
---|
| 620 | + * |
---|
| 621 | + * platform_shutdown is called by the platform subsystem to alert |
---|
| 622 | + * the driver that a shutdown, reboot, or kexec is happening and |
---|
| 623 | + * device must be disabled. |
---|
| 624 | + */ |
---|
| 625 | +static void optee_shutdown(struct platform_device *pdev) |
---|
| 626 | +{ |
---|
| 627 | + optee_disable_shm_cache(platform_get_drvdata(pdev)); |
---|
| 628 | +} |
---|
| 629 | + |
---|
| 630 | +static int optee_probe(struct platform_device *pdev) |
---|
543 | 631 | { |
---|
544 | 632 | optee_invoke_fn *invoke_fn; |
---|
545 | | - struct tee_shm_pool *pool; |
---|
| 633 | + struct tee_shm_pool *pool = ERR_PTR(-EINVAL); |
---|
546 | 634 | struct optee *optee = NULL; |
---|
547 | 635 | void *memremaped_shm = NULL; |
---|
548 | 636 | struct tee_device *teedev; |
---|
| 637 | + struct tee_context *ctx; |
---|
549 | 638 | u32 sec_caps; |
---|
550 | 639 | int rc; |
---|
551 | 640 | |
---|
552 | | - invoke_fn = get_invoke_func(np); |
---|
| 641 | + /* |
---|
| 642 | + * The kernel may have crashed at the same time that all available |
---|
| 643 | + * secure world threads were suspended and we cannot reschedule the |
---|
| 644 | + * suspended threads without access to the crashed kernel's wait_queue. |
---|
| 645 | + * Therefore, we cannot reliably initialize the OP-TEE driver in the |
---|
| 646 | + * kdump kernel. |
---|
| 647 | + */ |
---|
| 648 | + if (is_kdump_kernel()) |
---|
| 649 | + return -ENODEV; |
---|
| 650 | + |
---|
| 651 | + invoke_fn = get_invoke_func(&pdev->dev); |
---|
553 | 652 | if (IS_ERR(invoke_fn)) |
---|
554 | | - return (void *)invoke_fn; |
---|
| 653 | + return PTR_ERR(invoke_fn); |
---|
555 | 654 | |
---|
556 | 655 | if (!optee_msg_api_uid_is_optee_api(invoke_fn)) { |
---|
557 | 656 | pr_warn("api uid mismatch\n"); |
---|
558 | | - return ERR_PTR(-EINVAL); |
---|
| 657 | + return -EINVAL; |
---|
559 | 658 | } |
---|
560 | 659 | |
---|
561 | 660 | optee_msg_get_os_revision(invoke_fn); |
---|
562 | 661 | |
---|
563 | 662 | if (!optee_msg_api_revision_is_compatible(invoke_fn)) { |
---|
564 | 663 | pr_warn("api revision mismatch\n"); |
---|
565 | | - return ERR_PTR(-EINVAL); |
---|
| 664 | + return -EINVAL; |
---|
566 | 665 | } |
---|
567 | 666 | |
---|
568 | 667 | if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps)) { |
---|
569 | 668 | pr_warn("capabilities mismatch\n"); |
---|
570 | | - return ERR_PTR(-EINVAL); |
---|
| 669 | + return -EINVAL; |
---|
571 | 670 | } |
---|
572 | 671 | |
---|
573 | 672 | /* |
---|
574 | | - * We have no other option for shared memory, if secure world |
---|
575 | | - * doesn't have any reserved memory we can use we can't continue. |
---|
| 673 | + * Try to use dynamic shared memory if possible |
---|
576 | 674 | */ |
---|
577 | | - if (!(sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM)) |
---|
578 | | - return ERR_PTR(-EINVAL); |
---|
| 675 | + if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) |
---|
| 676 | + pool = optee_config_dyn_shm(); |
---|
579 | 677 | |
---|
580 | | - pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm, sec_caps); |
---|
| 678 | + /* |
---|
| 679 | + * If dynamic shared memory is not available or failed - try static one |
---|
| 680 | + */ |
---|
| 681 | + if (IS_ERR(pool) && (sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM)) |
---|
| 682 | + pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm); |
---|
| 683 | + |
---|
581 | 684 | if (IS_ERR(pool)) |
---|
582 | | - return (void *)pool; |
---|
| 685 | + return PTR_ERR(pool); |
---|
583 | 686 | |
---|
584 | 687 | optee = kzalloc(sizeof(*optee), GFP_KERNEL); |
---|
585 | 688 | if (!optee) { |
---|
.. | .. |
---|
618 | 721 | optee_supp_init(&optee->supp); |
---|
619 | 722 | optee->memremaped_shm = memremaped_shm; |
---|
620 | 723 | optee->pool = pool; |
---|
| 724 | + ctx = teedev_open(optee->teedev); |
---|
| 725 | + if (IS_ERR(ctx)) { |
---|
| 726 | + rc = PTR_ERR(ctx); |
---|
| 727 | + goto err; |
---|
| 728 | + } |
---|
| 729 | + optee->ctx = ctx; |
---|
621 | 730 | |
---|
622 | 731 | /* |
---|
623 | 732 | * Ensure that there are no pre-existing shm objects before enabling |
---|
.. | .. |
---|
630 | 739 | |
---|
631 | 740 | optee_enable_shm_cache(optee); |
---|
632 | 741 | |
---|
| 742 | + if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) |
---|
| 743 | + pr_info("dynamic shared memory is enabled\n"); |
---|
| 744 | + |
---|
| 745 | + platform_set_drvdata(pdev, optee); |
---|
| 746 | + |
---|
| 747 | + rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES); |
---|
| 748 | + if (rc) { |
---|
| 749 | + optee_remove(pdev); |
---|
| 750 | + return rc; |
---|
| 751 | + } |
---|
| 752 | + |
---|
633 | 753 | pr_info("initialized driver\n"); |
---|
634 | | - return optee; |
---|
| 754 | + return 0; |
---|
635 | 755 | err: |
---|
636 | 756 | if (optee) { |
---|
637 | 757 | /* |
---|
.. | .. |
---|
647 | 767 | tee_shm_pool_free(pool); |
---|
648 | 768 | if (memremaped_shm) |
---|
649 | 769 | memunmap(memremaped_shm); |
---|
650 | | - return ERR_PTR(rc); |
---|
| 770 | + return rc; |
---|
651 | 771 | } |
---|
652 | 772 | |
---|
653 | | -static void optee_remove(struct optee *optee) |
---|
654 | | -{ |
---|
655 | | - /* |
---|
656 | | - * Ask OP-TEE to free all cached shared memory objects to decrease |
---|
657 | | - * reference counters and also avoid wild pointers in secure world |
---|
658 | | - * into the old shared memory range. |
---|
659 | | - */ |
---|
660 | | - optee_disable_shm_cache(optee); |
---|
661 | | - |
---|
662 | | - /* |
---|
663 | | - * The two devices has to be unregistered before we can free the |
---|
664 | | - * other resources. |
---|
665 | | - */ |
---|
666 | | - tee_device_unregister(optee->supp_teedev); |
---|
667 | | - tee_device_unregister(optee->teedev); |
---|
668 | | - |
---|
669 | | - tee_shm_pool_free(optee->pool); |
---|
670 | | - if (optee->memremaped_shm) |
---|
671 | | - memunmap(optee->memremaped_shm); |
---|
672 | | - optee_wait_queue_exit(&optee->wait_queue); |
---|
673 | | - optee_supp_uninit(&optee->supp); |
---|
674 | | - mutex_destroy(&optee->call_queue.mutex); |
---|
675 | | - |
---|
676 | | - kfree(optee); |
---|
677 | | -} |
---|
678 | | - |
---|
679 | | -static const struct of_device_id optee_match[] = { |
---|
| 773 | +static const struct of_device_id optee_dt_match[] = { |
---|
680 | 774 | { .compatible = "linaro,optee-tz" }, |
---|
681 | 775 | {}, |
---|
682 | 776 | }; |
---|
| 777 | +MODULE_DEVICE_TABLE(of, optee_dt_match); |
---|
683 | 778 | |
---|
684 | | -static struct optee *optee_svc; |
---|
685 | | - |
---|
686 | | -static int __init optee_driver_init(void) |
---|
687 | | -{ |
---|
688 | | - struct device_node *fw_np; |
---|
689 | | - struct device_node *np; |
---|
690 | | - struct optee *optee; |
---|
691 | | - |
---|
692 | | - /* Node is supposed to be below /firmware */ |
---|
693 | | - fw_np = of_find_node_by_name(NULL, "firmware"); |
---|
694 | | - if (!fw_np) |
---|
695 | | - return -ENODEV; |
---|
696 | | - |
---|
697 | | - np = of_find_matching_node(fw_np, optee_match); |
---|
698 | | - if (!np || !of_device_is_available(np)) { |
---|
699 | | - of_node_put(np); |
---|
700 | | - return -ENODEV; |
---|
701 | | - } |
---|
702 | | - |
---|
703 | | - optee = optee_probe(np); |
---|
704 | | - of_node_put(np); |
---|
705 | | - |
---|
706 | | - if (IS_ERR(optee)) |
---|
707 | | - return PTR_ERR(optee); |
---|
708 | | - |
---|
709 | | - optee_svc = optee; |
---|
710 | | - |
---|
711 | | - return 0; |
---|
712 | | -} |
---|
713 | | -module_init(optee_driver_init); |
---|
714 | | - |
---|
715 | | -static void __exit optee_driver_exit(void) |
---|
716 | | -{ |
---|
717 | | - struct optee *optee = optee_svc; |
---|
718 | | - |
---|
719 | | - optee_svc = NULL; |
---|
720 | | - if (optee) |
---|
721 | | - optee_remove(optee); |
---|
722 | | -} |
---|
723 | | -module_exit(optee_driver_exit); |
---|
| 779 | +static struct platform_driver optee_driver = { |
---|
| 780 | + .probe = optee_probe, |
---|
| 781 | + .remove = optee_remove, |
---|
| 782 | + .shutdown = optee_shutdown, |
---|
| 783 | + .driver = { |
---|
| 784 | + .name = "optee", |
---|
| 785 | + .of_match_table = optee_dt_match, |
---|
| 786 | + }, |
---|
| 787 | +}; |
---|
| 788 | +module_platform_driver(optee_driver); |
---|
724 | 789 | |
---|
725 | 790 | MODULE_AUTHOR("Linaro"); |
---|
726 | 791 | MODULE_DESCRIPTION("OP-TEE driver"); |
---|
727 | 792 | MODULE_SUPPORTED_DEVICE(""); |
---|
728 | 793 | MODULE_VERSION("1.0"); |
---|
729 | 794 | MODULE_LICENSE("GPL v2"); |
---|
| 795 | +MODULE_ALIAS("platform:optee"); |
---|