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