1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Driver for Qualcomm Secure Execution Environment (SEE) interface (QSEECOM). 4 * Responsible for setting up and managing QSEECOM client devices. 5 * 6 * Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com> 7 */ 8 #include <linux/auxiliary_bus.h> 9 #include <linux/module.h> 10 #include <linux/platform_device.h> 11 #include <linux/slab.h> 12 #include <linux/types.h> 13 14 #include <linux/firmware/qcom/qcom_qseecom.h> 15 #include <linux/firmware/qcom/qcom_scm.h> 16 17 struct qseecom_app_desc { 18 const char *app_name; 19 const char *dev_name; 20 }; 21 22 static void qseecom_client_release(struct device *dev) 23 { 24 struct qseecom_client *client; 25 26 client = container_of(dev, struct qseecom_client, aux_dev.dev); 27 kfree(client); 28 } 29 30 static void qseecom_client_remove(void *data) 31 { 32 struct qseecom_client *client = data; 33 34 auxiliary_device_delete(&client->aux_dev); 35 auxiliary_device_uninit(&client->aux_dev); 36 } 37 38 static int qseecom_client_register(struct platform_device *qseecom_dev, 39 const struct qseecom_app_desc *desc) 40 { 41 struct qseecom_client *client; 42 u32 app_id; 43 int ret; 44 45 /* Try to find the app ID, skip device if not found */ 46 ret = qcom_scm_qseecom_app_get_id(desc->app_name, &app_id); 47 if (ret) 48 return ret == -ENOENT ? 0 : ret; 49 50 dev_info(&qseecom_dev->dev, "setting up client for %s\n", desc->app_name); 51 52 /* Allocate and set-up the client device */ 53 client = kzalloc(sizeof(*client), GFP_KERNEL); 54 if (!client) 55 return -ENOMEM; 56 57 client->aux_dev.name = desc->dev_name; 58 client->aux_dev.dev.parent = &qseecom_dev->dev; 59 client->aux_dev.dev.release = qseecom_client_release; 60 client->app_id = app_id; 61 62 ret = auxiliary_device_init(&client->aux_dev); 63 if (ret) { 64 kfree(client); 65 return ret; 66 } 67 68 ret = auxiliary_device_add(&client->aux_dev); 69 if (ret) { 70 auxiliary_device_uninit(&client->aux_dev); 71 return ret; 72 } 73 74 ret = devm_add_action_or_reset(&qseecom_dev->dev, qseecom_client_remove, client); 75 if (ret) 76 return ret; 77 78 return 0; 79 } 80 81 /* 82 * List of supported applications. One client device will be created per entry, 83 * assuming the app has already been loaded (usually by firmware bootloaders) 84 * and its ID can be queried successfully. 85 */ 86 static const struct qseecom_app_desc qcom_qseecom_apps[] = { 87 { "qcom.tz.uefisecapp", "uefisecapp" }, 88 }; 89 90 static int qcom_qseecom_probe(struct platform_device *qseecom_dev) 91 { 92 int ret; 93 int i; 94 95 /* Set up client devices for each base application */ 96 for (i = 0; i < ARRAY_SIZE(qcom_qseecom_apps); i++) { 97 ret = qseecom_client_register(qseecom_dev, &qcom_qseecom_apps[i]); 98 if (ret) 99 return ret; 100 } 101 102 return 0; 103 } 104 105 static struct platform_driver qcom_qseecom_driver = { 106 .driver = { 107 .name = "qcom_qseecom", 108 }, 109 .probe = qcom_qseecom_probe, 110 }; 111 112 static int __init qcom_qseecom_init(void) 113 { 114 return platform_driver_register(&qcom_qseecom_driver); 115 } 116 subsys_initcall(qcom_qseecom_init); 117 118 MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>"); 119 MODULE_DESCRIPTION("Driver for the Qualcomm SEE (QSEECOM) interface"); 120 MODULE_LICENSE("GPL"); 121