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