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