xref: /linux/drivers/firmware/qcom/qcom_pas_tee.c (revision edc84a9396acf1a0e78c46230dd0bcee1b84ac53)
1*b6f7978dSSumit Garg // SPDX-License-Identifier: GPL-2.0
2*b6f7978dSSumit Garg /*
3*b6f7978dSSumit Garg  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4*b6f7978dSSumit Garg  */
5*b6f7978dSSumit Garg 
6*b6f7978dSSumit Garg #include <linux/delay.h>
7*b6f7978dSSumit Garg #include <linux/of.h>
8*b6f7978dSSumit Garg #include <linux/firmware/qcom/qcom_pas.h>
9*b6f7978dSSumit Garg #include <linux/kernel.h>
10*b6f7978dSSumit Garg #include <linux/module.h>
11*b6f7978dSSumit Garg #include <linux/slab.h>
12*b6f7978dSSumit Garg #include <linux/tee_drv.h>
13*b6f7978dSSumit Garg #include <linux/uuid.h>
14*b6f7978dSSumit Garg 
15*b6f7978dSSumit Garg #include "qcom_pas.h"
16*b6f7978dSSumit Garg 
17*b6f7978dSSumit Garg /*
18*b6f7978dSSumit Garg  * Peripheral Authentication Service (PAS) supported.
19*b6f7978dSSumit Garg  *
20*b6f7978dSSumit Garg  * [in]  params[0].value.a:	Unique 32bit remote processor identifier
21*b6f7978dSSumit Garg  */
22*b6f7978dSSumit Garg #define TA_QCOM_PAS_IS_SUPPORTED		1
23*b6f7978dSSumit Garg 
24*b6f7978dSSumit Garg /*
25*b6f7978dSSumit Garg  * PAS capabilities.
26*b6f7978dSSumit Garg  *
27*b6f7978dSSumit Garg  * [in]  params[0].value.a:	Unique 32bit remote processor identifier
28*b6f7978dSSumit Garg  * [out] params[1].value.a:	PAS capability flags
29*b6f7978dSSumit Garg  */
30*b6f7978dSSumit Garg #define TA_QCOM_PAS_CAPABILITIES		2
31*b6f7978dSSumit Garg 
32*b6f7978dSSumit Garg /*
33*b6f7978dSSumit Garg  * PAS image initialization.
34*b6f7978dSSumit Garg  *
35*b6f7978dSSumit Garg  * [in]  params[0].value.a:	Unique 32bit remote processor identifier
36*b6f7978dSSumit Garg  * [in]  params[1].memref:	Loadable firmware metadata
37*b6f7978dSSumit Garg  */
38*b6f7978dSSumit Garg #define TA_QCOM_PAS_INIT_IMAGE			3
39*b6f7978dSSumit Garg 
40*b6f7978dSSumit Garg /*
41*b6f7978dSSumit Garg  * PAS memory setup.
42*b6f7978dSSumit Garg  *
43*b6f7978dSSumit Garg  * [in]  params[0].value.a:	Unique 32bit remote processor identifier
44*b6f7978dSSumit Garg  * [in]  params[0].value.b:	Relocatable firmware size
45*b6f7978dSSumit Garg  * [in]  params[1].value.a:	32bit LSB relocatable firmware memory address
46*b6f7978dSSumit Garg  * [in]  params[1].value.b:	32bit MSB relocatable firmware memory address
47*b6f7978dSSumit Garg  */
48*b6f7978dSSumit Garg #define TA_QCOM_PAS_MEM_SETUP			4
49*b6f7978dSSumit Garg 
50*b6f7978dSSumit Garg /*
51*b6f7978dSSumit Garg  * PAS get resource table.
52*b6f7978dSSumit Garg  *
53*b6f7978dSSumit Garg  * [in]     params[0].value.a:	Unique 32bit remote processor identifier
54*b6f7978dSSumit Garg  * [inout]  params[1].memref:	Resource table config
55*b6f7978dSSumit Garg  */
56*b6f7978dSSumit Garg #define TA_QCOM_PAS_GET_RESOURCE_TABLE		5
57*b6f7978dSSumit Garg 
58*b6f7978dSSumit Garg /*
59*b6f7978dSSumit Garg  * PAS image authentication and co-processor reset.
60*b6f7978dSSumit Garg  *
61*b6f7978dSSumit Garg  * [in]  params[0].value.a:	Unique 32bit remote processor identifier
62*b6f7978dSSumit Garg  * [in]  params[0].value.b:	Firmware size
63*b6f7978dSSumit Garg  * [in]  params[1].value.a:	32bit LSB firmware memory address
64*b6f7978dSSumit Garg  * [in]  params[1].value.b:	32bit MSB firmware memory address
65*b6f7978dSSumit Garg  * [in]  params[2].memref:	Optional fw memory space shared/lent
66*b6f7978dSSumit Garg  */
67*b6f7978dSSumit Garg #define TA_QCOM_PAS_AUTH_AND_RESET		6
68*b6f7978dSSumit Garg 
69*b6f7978dSSumit Garg /*
70*b6f7978dSSumit Garg  * PAS co-processor set suspend/resume state.
71*b6f7978dSSumit Garg  *
72*b6f7978dSSumit Garg  * [in]  params[0].value.a:	Unique 32bit remote processor identifier
73*b6f7978dSSumit Garg  * [in]  params[0].value.b:	Co-processor state identifier
74*b6f7978dSSumit Garg  */
75*b6f7978dSSumit Garg #define TA_QCOM_PAS_SET_REMOTE_STATE		7
76*b6f7978dSSumit Garg 
77*b6f7978dSSumit Garg /*
78*b6f7978dSSumit Garg  * PAS co-processor shutdown.
79*b6f7978dSSumit Garg  *
80*b6f7978dSSumit Garg  * [in]  params[0].value.a:	Unique 32bit remote processor identifier
81*b6f7978dSSumit Garg  */
82*b6f7978dSSumit Garg #define TA_QCOM_PAS_SHUTDOWN			8
83*b6f7978dSSumit Garg 
84*b6f7978dSSumit Garg #define TEE_NUM_PARAMS				4
85*b6f7978dSSumit Garg 
86*b6f7978dSSumit Garg /**
87*b6f7978dSSumit Garg  * struct qcom_pas_tee_private - PAS service private data
88*b6f7978dSSumit Garg  * @dev:		PAS service device.
89*b6f7978dSSumit Garg  * @ctx:		TEE context handler.
90*b6f7978dSSumit Garg  * @session_id:		PAS TA session identifier.
91*b6f7978dSSumit Garg  */
92*b6f7978dSSumit Garg struct qcom_pas_tee_private {
93*b6f7978dSSumit Garg 	struct device *dev;
94*b6f7978dSSumit Garg 	struct tee_context *ctx;
95*b6f7978dSSumit Garg 	u32 session_id;
96*b6f7978dSSumit Garg };
97*b6f7978dSSumit Garg 
qcom_pas_tee_supported(struct device * dev,u32 pas_id)98*b6f7978dSSumit Garg static bool qcom_pas_tee_supported(struct device *dev, u32 pas_id)
99*b6f7978dSSumit Garg {
100*b6f7978dSSumit Garg 	struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
101*b6f7978dSSumit Garg 	struct tee_ioctl_invoke_arg inv_arg = {
102*b6f7978dSSumit Garg 		.func = TA_QCOM_PAS_IS_SUPPORTED,
103*b6f7978dSSumit Garg 		.session = data->session_id,
104*b6f7978dSSumit Garg 		.num_params = TEE_NUM_PARAMS
105*b6f7978dSSumit Garg 	};
106*b6f7978dSSumit Garg 	struct tee_param param[4] = {
107*b6f7978dSSumit Garg 		[0] = {
108*b6f7978dSSumit Garg 			.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
109*b6f7978dSSumit Garg 			.u.value.a = pas_id
110*b6f7978dSSumit Garg 		}
111*b6f7978dSSumit Garg 	};
112*b6f7978dSSumit Garg 	int ret;
113*b6f7978dSSumit Garg 
114*b6f7978dSSumit Garg 	ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
115*b6f7978dSSumit Garg 	if (ret < 0 || inv_arg.ret != 0) {
116*b6f7978dSSumit Garg 		dev_err(dev, "PAS not supported, pas_id: %d, ret: %d, err: 0x%x\n",
117*b6f7978dSSumit Garg 			pas_id, ret, inv_arg.ret);
118*b6f7978dSSumit Garg 		return false;
119*b6f7978dSSumit Garg 	}
120*b6f7978dSSumit Garg 
121*b6f7978dSSumit Garg 	return true;
122*b6f7978dSSumit Garg }
123*b6f7978dSSumit Garg 
qcom_pas_tee_init_image(struct device * dev,u32 pas_id,const void * metadata,size_t size,struct qcom_pas_context * ctx)124*b6f7978dSSumit Garg static int qcom_pas_tee_init_image(struct device *dev, u32 pas_id,
125*b6f7978dSSumit Garg 				   const void *metadata, size_t size,
126*b6f7978dSSumit Garg 				   struct qcom_pas_context *ctx)
127*b6f7978dSSumit Garg {
128*b6f7978dSSumit Garg 	struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
129*b6f7978dSSumit Garg 	struct tee_ioctl_invoke_arg inv_arg = {
130*b6f7978dSSumit Garg 		.func = TA_QCOM_PAS_INIT_IMAGE,
131*b6f7978dSSumit Garg 		.session = data->session_id,
132*b6f7978dSSumit Garg 		.num_params = TEE_NUM_PARAMS
133*b6f7978dSSumit Garg 	};
134*b6f7978dSSumit Garg 	struct tee_param param[4] = {
135*b6f7978dSSumit Garg 		[0] = {
136*b6f7978dSSumit Garg 			.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
137*b6f7978dSSumit Garg 			.u.value.a = pas_id
138*b6f7978dSSumit Garg 		},
139*b6f7978dSSumit Garg 		[1] = {
140*b6f7978dSSumit Garg 			.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
141*b6f7978dSSumit Garg 		}
142*b6f7978dSSumit Garg 	};
143*b6f7978dSSumit Garg 	struct tee_shm *mdata_shm;
144*b6f7978dSSumit Garg 	u8 *mdata_buf = NULL;
145*b6f7978dSSumit Garg 	int ret;
146*b6f7978dSSumit Garg 
147*b6f7978dSSumit Garg 	mdata_shm = tee_shm_alloc_kernel_buf(data->ctx, size);
148*b6f7978dSSumit Garg 	if (IS_ERR(mdata_shm)) {
149*b6f7978dSSumit Garg 		dev_err(dev, "mdata_shm allocation failed\n");
150*b6f7978dSSumit Garg 		return PTR_ERR(mdata_shm);
151*b6f7978dSSumit Garg 	}
152*b6f7978dSSumit Garg 
153*b6f7978dSSumit Garg 	mdata_buf = tee_shm_get_va(mdata_shm, 0);
154*b6f7978dSSumit Garg 	if (IS_ERR(mdata_buf)) {
155*b6f7978dSSumit Garg 		dev_err(dev, "mdata_buf get VA failed\n");
156*b6f7978dSSumit Garg 		tee_shm_free(mdata_shm);
157*b6f7978dSSumit Garg 		return PTR_ERR(mdata_buf);
158*b6f7978dSSumit Garg 	}
159*b6f7978dSSumit Garg 	memcpy(mdata_buf, metadata, size);
160*b6f7978dSSumit Garg 
161*b6f7978dSSumit Garg 	param[1].u.memref.shm = mdata_shm;
162*b6f7978dSSumit Garg 	param[1].u.memref.size = size;
163*b6f7978dSSumit Garg 
164*b6f7978dSSumit Garg 	ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
165*b6f7978dSSumit Garg 	if (ret < 0 || inv_arg.ret != 0) {
166*b6f7978dSSumit Garg 		dev_err(dev, "PAS init image failed, pas_id: %d, ret: %d, err: 0x%x\n",
167*b6f7978dSSumit Garg 			pas_id, ret, inv_arg.ret);
168*b6f7978dSSumit Garg 		tee_shm_free(mdata_shm);
169*b6f7978dSSumit Garg 		return ret ?: -EINVAL;
170*b6f7978dSSumit Garg 	}
171*b6f7978dSSumit Garg 
172*b6f7978dSSumit Garg 	if (ctx)
173*b6f7978dSSumit Garg 		ctx->ptr = (void *)mdata_shm;
174*b6f7978dSSumit Garg 	else
175*b6f7978dSSumit Garg 		tee_shm_free(mdata_shm);
176*b6f7978dSSumit Garg 
177*b6f7978dSSumit Garg 	return ret;
178*b6f7978dSSumit Garg }
179*b6f7978dSSumit Garg 
qcom_pas_tee_mem_setup(struct device * dev,u32 pas_id,phys_addr_t addr,phys_addr_t size)180*b6f7978dSSumit Garg static int qcom_pas_tee_mem_setup(struct device *dev, u32 pas_id,
181*b6f7978dSSumit Garg 				  phys_addr_t addr, phys_addr_t size)
182*b6f7978dSSumit Garg {
183*b6f7978dSSumit Garg 	struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
184*b6f7978dSSumit Garg 	struct tee_ioctl_invoke_arg inv_arg = {
185*b6f7978dSSumit Garg 		.func = TA_QCOM_PAS_MEM_SETUP,
186*b6f7978dSSumit Garg 		.session = data->session_id,
187*b6f7978dSSumit Garg 		.num_params = TEE_NUM_PARAMS
188*b6f7978dSSumit Garg 	};
189*b6f7978dSSumit Garg 	struct tee_param param[4] = {
190*b6f7978dSSumit Garg 		[0] = {
191*b6f7978dSSumit Garg 			.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
192*b6f7978dSSumit Garg 			.u.value.a = pas_id,
193*b6f7978dSSumit Garg 			.u.value.b = size,
194*b6f7978dSSumit Garg 		},
195*b6f7978dSSumit Garg 		[1] = {
196*b6f7978dSSumit Garg 			.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
197*b6f7978dSSumit Garg 			.u.value.a = lower_32_bits(addr),
198*b6f7978dSSumit Garg 			.u.value.b = upper_32_bits(addr),
199*b6f7978dSSumit Garg 		}
200*b6f7978dSSumit Garg 	};
201*b6f7978dSSumit Garg 	int ret;
202*b6f7978dSSumit Garg 
203*b6f7978dSSumit Garg 	ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
204*b6f7978dSSumit Garg 	if (ret < 0 || inv_arg.ret != 0) {
205*b6f7978dSSumit Garg 		dev_err(dev, "PAS mem setup failed, pas_id: %d, ret: %d, err: 0x%x\n",
206*b6f7978dSSumit Garg 			pas_id, ret, inv_arg.ret);
207*b6f7978dSSumit Garg 		return ret ?: -EINVAL;
208*b6f7978dSSumit Garg 	}
209*b6f7978dSSumit Garg 
210*b6f7978dSSumit Garg 	return ret;
211*b6f7978dSSumit Garg }
212*b6f7978dSSumit Garg 
DEFINE_FREE(shm_free,struct tee_shm *,tee_shm_free (_T))213*b6f7978dSSumit Garg DEFINE_FREE(shm_free, struct tee_shm *, tee_shm_free(_T))
214*b6f7978dSSumit Garg 
215*b6f7978dSSumit Garg static void *qcom_pas_tee_get_rsc_table(struct device *dev,
216*b6f7978dSSumit Garg 					struct qcom_pas_context *ctx,
217*b6f7978dSSumit Garg 					void *input_rt, size_t input_rt_size,
218*b6f7978dSSumit Garg 					size_t *output_rt_size)
219*b6f7978dSSumit Garg {
220*b6f7978dSSumit Garg 	struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
221*b6f7978dSSumit Garg 	struct tee_ioctl_invoke_arg inv_arg = {
222*b6f7978dSSumit Garg 		.func = TA_QCOM_PAS_GET_RESOURCE_TABLE,
223*b6f7978dSSumit Garg 		.session = data->session_id,
224*b6f7978dSSumit Garg 		.num_params = TEE_NUM_PARAMS
225*b6f7978dSSumit Garg 	};
226*b6f7978dSSumit Garg 	struct tee_param param[4] = {
227*b6f7978dSSumit Garg 		[0] = {
228*b6f7978dSSumit Garg 			.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
229*b6f7978dSSumit Garg 			.u.value.a = ctx->pas_id,
230*b6f7978dSSumit Garg 		},
231*b6f7978dSSumit Garg 		[1] = {
232*b6f7978dSSumit Garg 			.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
233*b6f7978dSSumit Garg 			.u.memref.size = input_rt_size,
234*b6f7978dSSumit Garg 		}
235*b6f7978dSSumit Garg 	};
236*b6f7978dSSumit Garg 	void *rt_buf = NULL;
237*b6f7978dSSumit Garg 	int ret;
238*b6f7978dSSumit Garg 
239*b6f7978dSSumit Garg 	ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
240*b6f7978dSSumit Garg 	if (ret < 0 || inv_arg.ret != 0) {
241*b6f7978dSSumit Garg 		dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n",
242*b6f7978dSSumit Garg 			ctx->pas_id, ret, inv_arg.ret);
243*b6f7978dSSumit Garg 		return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL);
244*b6f7978dSSumit Garg 	}
245*b6f7978dSSumit Garg 
246*b6f7978dSSumit Garg 	if (param[1].u.memref.size >= input_rt_size) {
247*b6f7978dSSumit Garg 		struct tee_shm *rt_shm __free(shm_free) =
248*b6f7978dSSumit Garg 			tee_shm_alloc_kernel_buf(data->ctx,
249*b6f7978dSSumit Garg 						 param[1].u.memref.size);
250*b6f7978dSSumit Garg 		void *rt_shm_va;
251*b6f7978dSSumit Garg 
252*b6f7978dSSumit Garg 		if (IS_ERR_OR_NULL(rt_shm)) {
253*b6f7978dSSumit Garg 			dev_err(dev, "rt_shm allocation failed\n");
254*b6f7978dSSumit Garg 			rt_shm = NULL;
255*b6f7978dSSumit Garg 			return ERR_PTR(-ENOMEM);
256*b6f7978dSSumit Garg 		}
257*b6f7978dSSumit Garg 
258*b6f7978dSSumit Garg 		rt_shm_va = tee_shm_get_va(rt_shm, 0);
259*b6f7978dSSumit Garg 		if (IS_ERR(rt_shm_va)) {
260*b6f7978dSSumit Garg 			dev_err(dev, "rt_shm get VA failed\n");
261*b6f7978dSSumit Garg 			return ERR_CAST(rt_shm_va);
262*b6f7978dSSumit Garg 		}
263*b6f7978dSSumit Garg 		memcpy(rt_shm_va, input_rt, input_rt_size);
264*b6f7978dSSumit Garg 
265*b6f7978dSSumit Garg 		param[1].u.memref.shm = rt_shm;
266*b6f7978dSSumit Garg 		ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
267*b6f7978dSSumit Garg 		if (ret < 0 || inv_arg.ret != 0) {
268*b6f7978dSSumit Garg 			dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n",
269*b6f7978dSSumit Garg 				ctx->pas_id, ret, inv_arg.ret);
270*b6f7978dSSumit Garg 			return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL);
271*b6f7978dSSumit Garg 		}
272*b6f7978dSSumit Garg 
273*b6f7978dSSumit Garg 		if (param[1].u.memref.size) {
274*b6f7978dSSumit Garg 			*output_rt_size = param[1].u.memref.size;
275*b6f7978dSSumit Garg 			rt_buf = kmemdup(rt_shm_va, *output_rt_size, GFP_KERNEL);
276*b6f7978dSSumit Garg 			if (!rt_buf)
277*b6f7978dSSumit Garg 				return ERR_PTR(-ENOMEM);
278*b6f7978dSSumit Garg 		}
279*b6f7978dSSumit Garg 	} else {
280*b6f7978dSSumit Garg 		*output_rt_size = 0;
281*b6f7978dSSumit Garg 	}
282*b6f7978dSSumit Garg 
283*b6f7978dSSumit Garg 	return rt_buf;
284*b6f7978dSSumit Garg }
285*b6f7978dSSumit Garg 
__qcom_pas_tee_auth_and_reset(struct device * dev,u32 pas_id,phys_addr_t mem_phys,size_t mem_size)286*b6f7978dSSumit Garg static int __qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id,
287*b6f7978dSSumit Garg 					 phys_addr_t mem_phys, size_t mem_size)
288*b6f7978dSSumit Garg {
289*b6f7978dSSumit Garg 	struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
290*b6f7978dSSumit Garg 	struct tee_ioctl_invoke_arg inv_arg = {
291*b6f7978dSSumit Garg 		.func = TA_QCOM_PAS_AUTH_AND_RESET,
292*b6f7978dSSumit Garg 		.session = data->session_id,
293*b6f7978dSSumit Garg 		.num_params = TEE_NUM_PARAMS
294*b6f7978dSSumit Garg 	};
295*b6f7978dSSumit Garg 	struct tee_param param[4] = {
296*b6f7978dSSumit Garg 		[0] = {
297*b6f7978dSSumit Garg 			.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
298*b6f7978dSSumit Garg 			.u.value.a = pas_id,
299*b6f7978dSSumit Garg 			.u.value.b = mem_size,
300*b6f7978dSSumit Garg 		},
301*b6f7978dSSumit Garg 		[1] = {
302*b6f7978dSSumit Garg 			.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
303*b6f7978dSSumit Garg 			.u.value.a = lower_32_bits(mem_phys),
304*b6f7978dSSumit Garg 			.u.value.b = upper_32_bits(mem_phys),
305*b6f7978dSSumit Garg 		},
306*b6f7978dSSumit Garg 		/* Reserved for fw memory space to be shared or lent */
307*b6f7978dSSumit Garg 		[2] = {
308*b6f7978dSSumit Garg 			.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
309*b6f7978dSSumit Garg 		}
310*b6f7978dSSumit Garg 	};
311*b6f7978dSSumit Garg 	int ret;
312*b6f7978dSSumit Garg 
313*b6f7978dSSumit Garg 	ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
314*b6f7978dSSumit Garg 	if (ret < 0 || inv_arg.ret != 0) {
315*b6f7978dSSumit Garg 		dev_err(dev, "PAS auth reset failed, pas_id: %d, ret: %d, err: 0x%x\n",
316*b6f7978dSSumit Garg 			pas_id, ret, inv_arg.ret);
317*b6f7978dSSumit Garg 		return ret ?: -EINVAL;
318*b6f7978dSSumit Garg 	}
319*b6f7978dSSumit Garg 
320*b6f7978dSSumit Garg 	return ret;
321*b6f7978dSSumit Garg }
322*b6f7978dSSumit Garg 
qcom_pas_tee_auth_and_reset(struct device * dev,u32 pas_id)323*b6f7978dSSumit Garg static int qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id)
324*b6f7978dSSumit Garg {
325*b6f7978dSSumit Garg 	return __qcom_pas_tee_auth_and_reset(dev, pas_id, 0, 0);
326*b6f7978dSSumit Garg }
327*b6f7978dSSumit Garg 
qcom_pas_tee_prepare_and_auth_reset(struct device * dev,struct qcom_pas_context * ctx)328*b6f7978dSSumit Garg static int qcom_pas_tee_prepare_and_auth_reset(struct device *dev,
329*b6f7978dSSumit Garg 					       struct qcom_pas_context *ctx)
330*b6f7978dSSumit Garg {
331*b6f7978dSSumit Garg 	return __qcom_pas_tee_auth_and_reset(dev, ctx->pas_id, ctx->mem_phys,
332*b6f7978dSSumit Garg 					     ctx->mem_size);
333*b6f7978dSSumit Garg }
334*b6f7978dSSumit Garg 
qcom_pas_tee_set_remote_state(struct device * dev,u32 state,u32 pas_id)335*b6f7978dSSumit Garg static int qcom_pas_tee_set_remote_state(struct device *dev, u32 state,
336*b6f7978dSSumit Garg 					 u32 pas_id)
337*b6f7978dSSumit Garg {
338*b6f7978dSSumit Garg 	struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
339*b6f7978dSSumit Garg 	struct tee_ioctl_invoke_arg inv_arg = {
340*b6f7978dSSumit Garg 		.func = TA_QCOM_PAS_SET_REMOTE_STATE,
341*b6f7978dSSumit Garg 		.session = data->session_id,
342*b6f7978dSSumit Garg 		.num_params = TEE_NUM_PARAMS
343*b6f7978dSSumit Garg 	};
344*b6f7978dSSumit Garg 	struct tee_param param[4] = {
345*b6f7978dSSumit Garg 		[0] = {
346*b6f7978dSSumit Garg 			.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
347*b6f7978dSSumit Garg 			.u.value.a = pas_id,
348*b6f7978dSSumit Garg 			.u.value.b = state,
349*b6f7978dSSumit Garg 		}
350*b6f7978dSSumit Garg 	};
351*b6f7978dSSumit Garg 	int ret;
352*b6f7978dSSumit Garg 
353*b6f7978dSSumit Garg 	ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
354*b6f7978dSSumit Garg 	if (ret < 0 || inv_arg.ret != 0) {
355*b6f7978dSSumit Garg 		dev_err(dev, "PAS set remote state failed, pas_id: %d, ret: %d, err: 0x%x\n",
356*b6f7978dSSumit Garg 			pas_id, ret, inv_arg.ret);
357*b6f7978dSSumit Garg 		return ret ?: -EINVAL;
358*b6f7978dSSumit Garg 	}
359*b6f7978dSSumit Garg 
360*b6f7978dSSumit Garg 	return ret;
361*b6f7978dSSumit Garg }
362*b6f7978dSSumit Garg 
qcom_pas_tee_shutdown(struct device * dev,u32 pas_id)363*b6f7978dSSumit Garg static int qcom_pas_tee_shutdown(struct device *dev, u32 pas_id)
364*b6f7978dSSumit Garg {
365*b6f7978dSSumit Garg 	struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
366*b6f7978dSSumit Garg 	struct tee_ioctl_invoke_arg inv_arg = {
367*b6f7978dSSumit Garg 		.func = TA_QCOM_PAS_SHUTDOWN,
368*b6f7978dSSumit Garg 		.session = data->session_id,
369*b6f7978dSSumit Garg 		.num_params = TEE_NUM_PARAMS
370*b6f7978dSSumit Garg 	};
371*b6f7978dSSumit Garg 	struct tee_param param[4] = {
372*b6f7978dSSumit Garg 		[0] = {
373*b6f7978dSSumit Garg 			.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
374*b6f7978dSSumit Garg 			.u.value.a = pas_id
375*b6f7978dSSumit Garg 		}
376*b6f7978dSSumit Garg 	};
377*b6f7978dSSumit Garg 	int ret;
378*b6f7978dSSumit Garg 
379*b6f7978dSSumit Garg 	ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
380*b6f7978dSSumit Garg 	if (ret < 0 || inv_arg.ret != 0) {
381*b6f7978dSSumit Garg 		dev_err(dev, "PAS shutdown failed, pas_id: %d, ret: %d, err: 0x%x\n",
382*b6f7978dSSumit Garg 			pas_id, ret, inv_arg.ret);
383*b6f7978dSSumit Garg 		return ret ?: -EINVAL;
384*b6f7978dSSumit Garg 	}
385*b6f7978dSSumit Garg 
386*b6f7978dSSumit Garg 	return ret;
387*b6f7978dSSumit Garg }
388*b6f7978dSSumit Garg 
qcom_pas_tee_metadata_release(struct device * dev,struct qcom_pas_context * ctx)389*b6f7978dSSumit Garg static void qcom_pas_tee_metadata_release(struct device *dev,
390*b6f7978dSSumit Garg 					  struct qcom_pas_context *ctx)
391*b6f7978dSSumit Garg {
392*b6f7978dSSumit Garg 	struct tee_shm *mdata_shm = ctx->ptr;
393*b6f7978dSSumit Garg 
394*b6f7978dSSumit Garg 	tee_shm_free(mdata_shm);
395*b6f7978dSSumit Garg 	ctx->ptr = NULL;
396*b6f7978dSSumit Garg }
397*b6f7978dSSumit Garg 
398*b6f7978dSSumit Garg static struct qcom_pas_ops qcom_pas_ops_tee = {
399*b6f7978dSSumit Garg 	.drv_name		= "qcom-pas-tee",
400*b6f7978dSSumit Garg 	.supported		= qcom_pas_tee_supported,
401*b6f7978dSSumit Garg 	.init_image		= qcom_pas_tee_init_image,
402*b6f7978dSSumit Garg 	.mem_setup		= qcom_pas_tee_mem_setup,
403*b6f7978dSSumit Garg 	.get_rsc_table		= qcom_pas_tee_get_rsc_table,
404*b6f7978dSSumit Garg 	.auth_and_reset		= qcom_pas_tee_auth_and_reset,
405*b6f7978dSSumit Garg 	.prepare_and_auth_reset	= qcom_pas_tee_prepare_and_auth_reset,
406*b6f7978dSSumit Garg 	.set_remote_state	= qcom_pas_tee_set_remote_state,
407*b6f7978dSSumit Garg 	.shutdown		= qcom_pas_tee_shutdown,
408*b6f7978dSSumit Garg 	.metadata_release	= qcom_pas_tee_metadata_release,
409*b6f7978dSSumit Garg };
410*b6f7978dSSumit Garg 
optee_ctx_match(struct tee_ioctl_version_data * ver,const void * data)411*b6f7978dSSumit Garg static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
412*b6f7978dSSumit Garg {
413*b6f7978dSSumit Garg 	return ver->impl_id == TEE_IMPL_ID_OPTEE;
414*b6f7978dSSumit Garg }
415*b6f7978dSSumit Garg 
qcom_pas_tee_probe(struct tee_client_device * pas_dev)416*b6f7978dSSumit Garg static int qcom_pas_tee_probe(struct tee_client_device *pas_dev)
417*b6f7978dSSumit Garg {
418*b6f7978dSSumit Garg 	struct device *dev = &pas_dev->dev;
419*b6f7978dSSumit Garg 	struct qcom_pas_tee_private *data;
420*b6f7978dSSumit Garg 	struct tee_ioctl_open_session_arg sess_arg = {
421*b6f7978dSSumit Garg 		.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL
422*b6f7978dSSumit Garg 	};
423*b6f7978dSSumit Garg 	int ret;
424*b6f7978dSSumit Garg 
425*b6f7978dSSumit Garg 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
426*b6f7978dSSumit Garg 	if (!data)
427*b6f7978dSSumit Garg 		return -ENOMEM;
428*b6f7978dSSumit Garg 
429*b6f7978dSSumit Garg 	data->ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
430*b6f7978dSSumit Garg 	if (IS_ERR(data->ctx))
431*b6f7978dSSumit Garg 		return -ENODEV;
432*b6f7978dSSumit Garg 
433*b6f7978dSSumit Garg 	export_uuid(sess_arg.uuid, &pas_dev->id.uuid);
434*b6f7978dSSumit Garg 	ret = tee_client_open_session(data->ctx, &sess_arg, NULL);
435*b6f7978dSSumit Garg 	if (ret < 0 || sess_arg.ret != 0) {
436*b6f7978dSSumit Garg 		dev_err(dev, "tee_client_open_session failed, ret: %d, err: 0x%x\n",
437*b6f7978dSSumit Garg 			ret, sess_arg.ret);
438*b6f7978dSSumit Garg 		tee_client_close_context(data->ctx);
439*b6f7978dSSumit Garg 		return ret ?: -EINVAL;
440*b6f7978dSSumit Garg 	}
441*b6f7978dSSumit Garg 
442*b6f7978dSSumit Garg 	data->session_id = sess_arg.session;
443*b6f7978dSSumit Garg 	dev_set_drvdata(dev, data);
444*b6f7978dSSumit Garg 	qcom_pas_ops_tee.dev = dev;
445*b6f7978dSSumit Garg 	qcom_pas_ops_register(&qcom_pas_ops_tee);
446*b6f7978dSSumit Garg 
447*b6f7978dSSumit Garg 	return ret;
448*b6f7978dSSumit Garg }
449*b6f7978dSSumit Garg 
qcom_pas_tee_remove(struct tee_client_device * pas_dev)450*b6f7978dSSumit Garg static void qcom_pas_tee_remove(struct tee_client_device *pas_dev)
451*b6f7978dSSumit Garg {
452*b6f7978dSSumit Garg 	struct device *dev = &pas_dev->dev;
453*b6f7978dSSumit Garg 	struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
454*b6f7978dSSumit Garg 
455*b6f7978dSSumit Garg 	qcom_pas_ops_unregister();
456*b6f7978dSSumit Garg 	tee_client_close_session(data->ctx, data->session_id);
457*b6f7978dSSumit Garg 	tee_client_close_context(data->ctx);
458*b6f7978dSSumit Garg }
459*b6f7978dSSumit Garg 
460*b6f7978dSSumit Garg static const struct tee_client_device_id qcom_pas_tee_id_table[] = {
461*b6f7978dSSumit Garg 	{UUID_INIT(0xcff7d191, 0x7ca0, 0x4784,
462*b6f7978dSSumit Garg 		   0xaf, 0x13, 0x48, 0x22, 0x3b, 0x9a, 0x4f, 0xbe)},
463*b6f7978dSSumit Garg 	{}
464*b6f7978dSSumit Garg };
465*b6f7978dSSumit Garg MODULE_DEVICE_TABLE(tee, qcom_pas_tee_id_table);
466*b6f7978dSSumit Garg 
467*b6f7978dSSumit Garg static struct tee_client_driver optee_pas_tee_driver = {
468*b6f7978dSSumit Garg 	.probe		= qcom_pas_tee_probe,
469*b6f7978dSSumit Garg 	.remove		= qcom_pas_tee_remove,
470*b6f7978dSSumit Garg 	.id_table	= qcom_pas_tee_id_table,
471*b6f7978dSSumit Garg 	.driver		= {
472*b6f7978dSSumit Garg 		.name		= "qcom-pas-tee",
473*b6f7978dSSumit Garg 	},
474*b6f7978dSSumit Garg };
475*b6f7978dSSumit Garg 
476*b6f7978dSSumit Garg module_tee_client_driver(optee_pas_tee_driver);
477*b6f7978dSSumit Garg 
478*b6f7978dSSumit Garg MODULE_LICENSE("GPL");
479*b6f7978dSSumit Garg MODULE_DESCRIPTION("Qualcomm PAS TEE driver");
480