blob: 362a391a93319b667dfa3e4b3e3dafac601ab01f [file] [log] [blame]
Mona Hossaina5f1aab2012-03-29 10:18:07 -07001
Mona Hossainacea1022012-04-09 13:37:27 -07002
Mona Hossaind44a3842012-10-15 09:41:35 -07003/*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
Mona Hossain2892b6b2012-02-17 13:53:11 -08004 *
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08005 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Mona Hossain2892b6b2012-02-17 13:53:11 -08006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 and
9 * only version 2 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#define pr_fmt(fmt) "QSEECOM: %s: " fmt, __func__
18
19#include <linux/kernel.h>
20#include <linux/slab.h>
21#include <linux/module.h>
22#include <linux/fs.h>
23#include <linux/platform_device.h>
24#include <linux/debugfs.h>
25#include <linux/cdev.h>
26#include <linux/uaccess.h>
27#include <linux/sched.h>
28#include <linux/list.h>
29#include <linux/mutex.h>
30#include <linux/io.h>
Mitchel Humpherys4f8be2e2012-09-06 10:41:41 -070031#include <linux/msm_ion.h>
Mona Hossain2892b6b2012-02-17 13:53:11 -080032#include <linux/types.h>
33#include <linux/clk.h>
34#include <linux/qseecom.h>
Mona Hossaind44a3842012-10-15 09:41:35 -070035#include <linux/elf.h>
36#include <linux/firmware.h>
Mona Hossainacea1022012-04-09 13:37:27 -070037#include <linux/freezer.h>
Mona Hossainf1f2ed62012-11-15 19:51:33 -080038#include <linux/scatterlist.h>
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070039#include <mach/board.h>
Mona Hossain2892b6b2012-02-17 13:53:11 -080040#include <mach/msm_bus.h>
41#include <mach/msm_bus_board.h>
42#include <mach/scm.h>
Stephen Boyd77db8bb2012-06-27 15:15:16 -070043#include <mach/subsystem_restart.h>
Ramesh Masavarapuff377032012-09-14 12:11:32 -070044#include <mach/socinfo.h>
Mona Hossain803c3d92012-11-21 13:33:42 -080045#include <mach/qseecomi.h>
Mona Hossain2892b6b2012-02-17 13:53:11 -080046#include "qseecom_legacy.h"
Mona Hossaind44a3842012-10-15 09:41:35 -070047#include "qseecom_kernel.h"
Mona Hossain2892b6b2012-02-17 13:53:11 -080048
49#define QSEECOM_DEV "qseecom"
50#define QSEOS_VERSION_13 0x13
51#define QSEOS_VERSION_14 0x14
Mona Hossain05c73562012-10-29 17:49:01 -070052#define QSEEE_VERSION_00 0x400000
Mona Hossain5b76a622012-11-15 20:09:08 -080053#define QSEE_VERSION_01 0x401000
54#define QSEE_VERSION_02 0x402000
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080055#define QSEE_VERSION_03 0x403000
Mona Hossain5b76a622012-11-15 20:09:08 -080056
Mona Hossain05c73562012-10-29 17:49:01 -070057
58#define QSEOS_CHECK_VERSION_CMD 0x00001803
Mona Hossain2892b6b2012-02-17 13:53:11 -080059
Mona Hossaind39e33b2012-11-05 13:36:40 -080060#define QSEE_CE_CLK_100MHZ 100000000
Mona Hossaind39e33b2012-11-05 13:36:40 -080061
Mona Hossain13dd8922013-01-03 06:11:09 -080062#define QSEECOM_MAX_SG_ENTRY 512
Mona Hossainf1f2ed62012-11-15 19:51:33 -080063
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070064enum qseecom_clk_definitions {
65 CLK_DFAB = 0,
66 CLK_SFPB,
67};
68
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080069enum qseecom_client_handle_type {
70 QSEECOM_CLIENT_APP = 0,
71 QSEECOM_LISTENER_SERVICE,
72 QSEECOM_SECURE_SERVICE,
73 QSEECOM_GENERIC,
74};
75
Mona Hossain2892b6b2012-02-17 13:53:11 -080076static struct class *driver_class;
77static dev_t qseecom_device_no;
78static struct cdev qseecom_cdev;
79
80/* Data structures used in legacy support */
81static void *pil;
82static uint32_t pil_ref_cnt;
83static DEFINE_MUTEX(pil_access_lock);
84
Mona Hossain2892b6b2012-02-17 13:53:11 -080085static DEFINE_MUTEX(qsee_bw_mutex);
86static DEFINE_MUTEX(app_access_lock);
87
Mona Hossain2892b6b2012-02-17 13:53:11 -080088struct qseecom_registered_listener_list {
89 struct list_head list;
90 struct qseecom_register_listener_req svc;
91 u8 *sb_reg_req;
92 u8 *sb_virt;
93 s32 sb_phys;
94 size_t sb_length;
95 struct ion_handle *ihandle; /* Retrieve phy addr */
96
97 wait_queue_head_t rcv_req_wq;
98 int rcv_req_flag;
99};
100
101struct qseecom_registered_app_list {
102 struct list_head list;
103 u32 app_id;
104 u32 ref_cnt;
105};
106
Mona Hossaind44a3842012-10-15 09:41:35 -0700107struct qseecom_registered_kclient_list {
108 struct list_head list;
109 struct qseecom_handle *handle;
110};
111
Mona Hossain17a4faf2013-03-22 16:40:56 -0700112struct qseecom_clk {
113 struct clk *ce_core_clk;
114 struct clk *ce_clk;
115 struct clk *ce_core_src_clk;
116 struct clk *ce_bus_clk;
117};
118
Mona Hossain2892b6b2012-02-17 13:53:11 -0800119struct qseecom_control {
120 struct ion_client *ion_clnt; /* Ion client */
121 struct list_head registered_listener_list_head;
122 spinlock_t registered_listener_list_lock;
123
124 struct list_head registered_app_list_head;
125 spinlock_t registered_app_list_lock;
126
Mona Hossaind44a3842012-10-15 09:41:35 -0700127 struct list_head registered_kclient_list_head;
128 spinlock_t registered_kclient_list_lock;
129
Mona Hossain2892b6b2012-02-17 13:53:11 -0800130 wait_queue_head_t send_resp_wq;
131 int send_resp_flag;
132
133 uint32_t qseos_version;
Mona Hossain05c73562012-10-29 17:49:01 -0700134 uint32_t qsee_version;
Ramesh Masavarapuff377032012-09-14 12:11:32 -0700135 struct device *pdev;
Mona Hossain05c73562012-10-29 17:49:01 -0700136 bool commonlib_loaded;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700137
138 int qsee_bw_count;
139 int qsee_sfpb_bw_count;
140
141 uint32_t qsee_perf_client;
142 struct qseecom_clk qsee;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800143};
144
145struct qseecom_client_handle {
146 u32 app_id;
147 u8 *sb_virt;
148 s32 sb_phys;
149 uint32_t user_virt_sb_base;
150 size_t sb_length;
151 struct ion_handle *ihandle; /* Retrieve phy addr */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800152 bool perf_enabled;
153 bool fast_load_enabled;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800154};
155
156struct qseecom_listener_handle {
157 u32 id;
158};
159
160static struct qseecom_control qseecom;
161
162struct qseecom_dev_handle {
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800163 enum qseecom_client_handle_type type;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800164 union {
165 struct qseecom_client_handle client;
166 struct qseecom_listener_handle listener;
167 };
168 bool released;
169 int abort;
170 wait_queue_head_t abort_wq;
171 atomic_t ioctl_count;
172};
173
Mona Hossainf1f2ed62012-11-15 19:51:33 -0800174struct qseecom_sg_entry {
175 uint32_t phys_addr;
176 uint32_t len;
177};
178
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700179/* Function proto types */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800180static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
181static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700182
Mona Hossain2892b6b2012-02-17 13:53:11 -0800183static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
Mona Hossain0af10ab2012-02-28 18:26:41 -0800184 struct qseecom_register_listener_req *svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -0800185{
186 struct qseecom_registered_listener_list *ptr;
187 int unique = 1;
188 unsigned long flags;
189
190 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
191 list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
Mona Hossain0af10ab2012-02-28 18:26:41 -0800192 if (ptr->svc.listener_id == svc->listener_id) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800193 pr_err("Service id: %u is already registered\n",
194 ptr->svc.listener_id);
195 unique = 0;
196 break;
197 }
198 }
199 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
200 return unique;
201}
202
203static struct qseecom_registered_listener_list *__qseecom_find_svc(
204 int32_t listener_id)
205{
206 struct qseecom_registered_listener_list *entry = NULL;
207 unsigned long flags;
208
209 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
210 list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
211 {
212 if (entry->svc.listener_id == listener_id)
213 break;
214 }
215 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
216 return entry;
217}
218
219static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
220 struct qseecom_dev_handle *handle,
221 struct qseecom_register_listener_req *listener)
222{
223 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800224 struct qseecom_register_listener_ireq req;
225 struct qseecom_command_scm_resp resp;
226 ion_phys_addr_t pa;
227
228 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800229 svc->ihandle = ion_import_dma_buf(qseecom.ion_clnt,
230 listener->ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800231 if (svc->ihandle == NULL) {
232 pr_err("Ion client could not retrieve the handle\n");
233 return -ENOMEM;
234 }
235
236 /* Get the physical address of the ION BUF */
237 ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
238
239 /* Populate the structure for sending scm call to load image */
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700240 svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800241 svc->sb_phys = pa;
242
243 if (qseecom.qseos_version == QSEOS_VERSION_14) {
244 req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
245 req.listener_id = svc->svc.listener_id;
246 req.sb_len = svc->sb_length;
247 req.sb_ptr = (void *)svc->sb_phys;
248
249 resp.result = QSEOS_RESULT_INCOMPLETE;
250
251 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
252 sizeof(req), &resp, sizeof(resp));
253 if (ret) {
254 pr_err("qseecom_scm_call failed with err: %d\n", ret);
255 return -EINVAL;
256 }
257
258 if (resp.result != QSEOS_RESULT_SUCCESS) {
259 pr_err("Error SB registration req: resp.result = %d\n",
260 resp.result);
261 return -EPERM;
262 }
263 } else {
264 struct qseecom_command cmd;
265 struct qseecom_response resp;
266 struct qse_pr_init_sb_req_s sb_init_req;
267 struct qse_pr_init_sb_rsp_s sb_init_rsp;
268
269 svc->sb_reg_req = kzalloc((sizeof(sb_init_req) +
270 sizeof(sb_init_rsp)), GFP_KERNEL);
271
272 sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
273 sb_init_req.listener_id = svc->svc.listener_id;
274 sb_init_req.sb_len = svc->sb_length;
275 sb_init_req.sb_ptr = svc->sb_phys;
276
277 memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
278
279 /* It will always be a new cmd from this method */
280 cmd.cmd_type = TZ_SCHED_CMD_NEW;
281 cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
282 cmd.sb_in_cmd_len = sizeof(sb_init_req);
283
284 resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
285
286 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd)
287 , &resp, sizeof(resp));
288
289 if (ret) {
290 pr_err("qseecom_scm_call failed with err: %d\n", ret);
291 return -EINVAL;
292 }
293
294 if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
295 pr_err("SB registration fail resp.cmd_status %d\n",
296 resp.cmd_status);
297 return -EINVAL;
298 }
299 memset(svc->sb_virt, 0, svc->sb_length);
300 }
301 return 0;
302}
303
304static int qseecom_register_listener(struct qseecom_dev_handle *data,
305 void __user *argp)
306{
307 int ret = 0;
308 unsigned long flags;
309 struct qseecom_register_listener_req rcvd_lstnr;
310 struct qseecom_registered_listener_list *new_entry;
311
312 ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
313 if (ret) {
314 pr_err("copy_from_user failed\n");
315 return ret;
316 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800317 data->listener.id = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800318 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain0af10ab2012-02-28 18:26:41 -0800319 if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800320 pr_err("Service is not unique and is already registered\n");
Mona Hossain0af10ab2012-02-28 18:26:41 -0800321 data->released = true;
322 return -EBUSY;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800323 }
324
325 new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
326 if (!new_entry) {
327 pr_err("kmalloc failed\n");
328 return -ENOMEM;
329 }
330 memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
331 new_entry->rcv_req_flag = 0;
332
333 new_entry->svc.listener_id = rcvd_lstnr.listener_id;
334 new_entry->sb_length = rcvd_lstnr.sb_size;
335 if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
336 pr_err("qseecom_set_sb_memoryfailed\n");
337 kzfree(new_entry);
338 return -ENOMEM;
339 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800340
Mona Hossain2892b6b2012-02-17 13:53:11 -0800341 data->listener.id = rcvd_lstnr.listener_id;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800342 init_waitqueue_head(&new_entry->rcv_req_wq);
343
344 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
345 list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
346 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
Mona Hossain0af10ab2012-02-28 18:26:41 -0800347
Mona Hossain2892b6b2012-02-17 13:53:11 -0800348 return ret;
349}
350
351static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
352{
353 int ret = 0;
354 unsigned long flags;
355 uint32_t unmap_mem = 0;
356 struct qseecom_register_listener_ireq req;
357 struct qseecom_registered_listener_list *ptr_svc = NULL;
358 struct qseecom_command_scm_resp resp;
359 struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
360
361 if (qseecom.qseos_version == QSEOS_VERSION_14) {
362 req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
363 req.listener_id = data->listener.id;
364 resp.result = QSEOS_RESULT_INCOMPLETE;
365
366 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
367 sizeof(req), &resp, sizeof(resp));
368 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700369 pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
370 ret, data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800371 return ret;
372 }
373
374 if (resp.result != QSEOS_RESULT_SUCCESS) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700375 pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
376 resp.result, data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800377 return -EPERM;
378 }
379 } else {
380 struct qse_pr_init_sb_req_s sb_init_req;
381 struct qseecom_command cmd;
382 struct qseecom_response resp;
383 struct qseecom_registered_listener_list *svc;
384
385 svc = __qseecom_find_svc(data->listener.id);
386 sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
387 sb_init_req.listener_id = data->listener.id;
388 sb_init_req.sb_len = 0;
389 sb_init_req.sb_ptr = 0;
390
391 memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
392
393 /* It will always be a new cmd from this method */
394 cmd.cmd_type = TZ_SCHED_CMD_NEW;
395 cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
396 cmd.sb_in_cmd_len = sizeof(sb_init_req);
397 resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
398
399 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd),
400 &resp, sizeof(resp));
401 if (ret) {
402 pr_err("qseecom_scm_call failed with err: %d\n", ret);
403 return ret;
404 }
405 kzfree(svc->sb_reg_req);
406 if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
407 pr_err("Error with SB initialization\n");
408 return -EPERM;
409 }
410 }
411 data->abort = 1;
412 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
413 list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
414 list) {
415 if (ptr_svc->svc.listener_id == data->listener.id) {
416 wake_up_all(&ptr_svc->rcv_req_wq);
417 break;
418 }
419 }
420 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
421
422 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700423 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800424 atomic_read(&data->ioctl_count) <= 1)) {
425 pr_err("Interrupted from abort\n");
426 ret = -ERESTARTSYS;
427 break;
428 }
429 }
430
431 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
432 list_for_each_entry(ptr_svc,
433 &qseecom.registered_listener_list_head,
434 list)
435 {
436 if (ptr_svc->svc.listener_id == data->listener.id) {
437 if (ptr_svc->sb_virt) {
438 unmap_mem = 1;
439 ihandle = ptr_svc->ihandle;
440 }
441 list_del(&ptr_svc->list);
442 kzfree(ptr_svc);
443 break;
444 }
445 }
446 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
447
448 /* Unmap the memory */
449 if (unmap_mem) {
450 if (!IS_ERR_OR_NULL(ihandle)) {
451 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
452 ion_free(qseecom.ion_clnt, ihandle);
453 }
454 }
455 data->released = true;
456 return ret;
457}
458
459static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
460 void __user *argp)
461{
462 ion_phys_addr_t pa;
463 int32_t ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800464 struct qseecom_set_sb_mem_param_req req;
465 uint32_t len;
466
467 /* Copy the relevant information needed for loading the image */
468 if (__copy_from_user(&req, (void __user *)argp, sizeof(req)))
469 return -EFAULT;
470
Mona Hossain2892b6b2012-02-17 13:53:11 -0800471 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800472 data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
473 req.ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800474 if (IS_ERR_OR_NULL(data->client.ihandle)) {
475 pr_err("Ion client could not retrieve the handle\n");
476 return -ENOMEM;
477 }
478 /* Get the physical address of the ION BUF */
479 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
480 /* Populate the structure for sending scm call to load image */
481 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700482 data->client.ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800483 data->client.sb_phys = pa;
484 data->client.sb_length = req.sb_len;
485 data->client.user_virt_sb_base = req.virt_sb_base;
486 return 0;
487}
488
Mona Hossain2892b6b2012-02-17 13:53:11 -0800489static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
490{
491 int ret;
492 ret = (qseecom.send_resp_flag != 0);
493 return ret || data->abort;
494}
495
496static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
497 struct qseecom_command_scm_resp *resp)
498{
499 int ret = 0;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800500 int rc = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800501 uint32_t lstnr;
502 unsigned long flags;
503 struct qseecom_client_listener_data_irsp send_data_rsp;
504 struct qseecom_registered_listener_list *ptr_svc = NULL;
505
506
507 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
508 lstnr = resp->data;
509 /*
510 * Wake up blocking lsitener service with the lstnr id
511 */
512 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
513 flags);
514 list_for_each_entry(ptr_svc,
515 &qseecom.registered_listener_list_head, list) {
516 if (ptr_svc->svc.listener_id == lstnr) {
517 ptr_svc->rcv_req_flag = 1;
518 wake_up_interruptible(&ptr_svc->rcv_req_wq);
519 break;
520 }
521 }
522 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
523 flags);
524 if (ptr_svc->svc.listener_id != lstnr) {
525 pr_warning("Service requested for does on exist\n");
526 return -ERESTARTSYS;
527 }
528 pr_debug("waking up rcv_req_wq and "
529 "waiting for send_resp_wq\n");
Mona Hossainacea1022012-04-09 13:37:27 -0700530 if (wait_event_freezable(qseecom.send_resp_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800531 __qseecom_listener_has_sent_rsp(data))) {
532 pr_warning("Interrupted: exiting send_cmd loop\n");
533 return -ERESTARTSYS;
534 }
535
536 if (data->abort) {
Mona Hossaina5f1aab2012-03-29 10:18:07 -0700537 pr_err("Aborting listener service %d\n",
538 data->listener.id);
Mona Hossain0b3a2792013-02-05 17:38:55 -0800539 rc = -ENODEV;
540 send_data_rsp.status = QSEOS_RESULT_FAILURE;
541 } else {
542 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800543 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800544
Mona Hossain2892b6b2012-02-17 13:53:11 -0800545 qseecom.send_resp_flag = 0;
546 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
547 send_data_rsp.listener_id = lstnr ;
548
549 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
550 (const void *)&send_data_rsp,
551 sizeof(send_data_rsp), resp,
552 sizeof(*resp));
553 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700554 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800555 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800556 return ret;
557 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800558 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
559 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
560 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
561 resp->result, data->client.app_id, lstnr);
562 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700563 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800564 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800565 if (rc)
566 return rc;
567
Mona Hossain2892b6b2012-02-17 13:53:11 -0800568 return ret;
569}
570
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700571static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
572{
573 int32_t ret;
574 struct qseecom_command_scm_resp resp;
575
576 /* SCM_CALL to check if app_id for the mentioned app exists */
577 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
578 sizeof(struct qseecom_check_app_ireq),
579 &resp, sizeof(resp));
580 if (ret) {
581 pr_err("scm_call to check if app is already loaded failed\n");
582 return -EINVAL;
583 }
584
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700585 if (resp.result == QSEOS_RESULT_FAILURE) {
586 return 0;
587 } else {
588 switch (resp.resp_type) {
589 /*qsee returned listener type response */
590 case QSEOS_LISTENER_ID:
591 pr_err("resp type is of listener type instead of app");
592 return -EINVAL;
593 break;
594 case QSEOS_APP_ID:
595 return resp.data;
596 default:
597 pr_err("invalid resp type (%d) from qsee",
598 resp.resp_type);
599 return -ENODEV;
600 break;
601 }
602 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700603}
604
Mona Hossain2892b6b2012-02-17 13:53:11 -0800605static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
606{
607 struct qseecom_registered_app_list *entry = NULL;
608 unsigned long flags = 0;
609 u32 app_id = 0;
610 struct ion_handle *ihandle; /* Ion handle */
611 struct qseecom_load_img_req load_img_req;
612 int32_t ret;
613 ion_phys_addr_t pa = 0;
614 uint32_t len;
615 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800616 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700617 struct qseecom_load_app_ireq load_req;
618
Mona Hossain2892b6b2012-02-17 13:53:11 -0800619 /* Copy the relevant information needed for loading the image */
620 if (__copy_from_user(&load_img_req,
621 (void __user *)argp,
622 sizeof(struct qseecom_load_img_req))) {
623 pr_err("copy_from_user failed\n");
624 return -EFAULT;
625 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700626 /* Vote for the SFPB clock */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800627 ret = qsee_vote_for_clock(data, CLK_SFPB);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700628 if (ret)
629 pr_warning("Unable to vote for SFPB clock");
Mona Hossain436b75f2012-11-20 17:10:40 -0800630 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
631 memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800632
Mona Hossain436b75f2012-11-20 17:10:40 -0800633 ret = __qseecom_check_app_exists(req);
634 if (ret < 0)
635 return ret;
636 else
637 app_id = ret;
638
639 if (app_id) {
640 pr_warn("App id %d (%s) already exists\n", app_id,
641 (char *)(req.app_name));
642 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
643 list_for_each_entry(entry,
644 &qseecom.registered_app_list_head, list){
645 if (entry->app_id == app_id) {
646 entry->ref_cnt++;
647 break;
648 }
649 }
650 spin_unlock_irqrestore(
651 &qseecom.registered_app_list_lock, flags);
652 } else {
653 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700654 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800655 /* Get the handle of the shared fd */
656 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800657 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800658 if (IS_ERR_OR_NULL(ihandle)) {
659 pr_err("Ion client could not retrieve the handle\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800660 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800661 return -ENOMEM;
662 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800663
Mona Hossain436b75f2012-11-20 17:10:40 -0800664 /* Get the physical address of the ION BUF */
665 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800666
Mona Hossain436b75f2012-11-20 17:10:40 -0800667 /* Populate the structure for sending scm call to load image */
668 memcpy(load_req.app_name, load_img_req.img_name,
669 MAX_APP_NAME_SIZE);
670 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
671 load_req.mdt_len = load_img_req.mdt_len;
672 load_req.img_len = load_img_req.img_len;
673 load_req.phy_addr = pa;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800674
Mona Hossain436b75f2012-11-20 17:10:40 -0800675 /* SCM_CALL to load the app and get the app_id back */
676 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700677 sizeof(struct qseecom_load_app_ireq),
678 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700679 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -0800680 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -0800681 if (!IS_ERR_OR_NULL(ihandle))
682 ion_free(qseecom.ion_clnt, ihandle);
683 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800684 return -EINVAL;
685 }
686
687 if (resp.result == QSEOS_RESULT_FAILURE) {
688 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700689 if (!IS_ERR_OR_NULL(ihandle))
690 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800691 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800692 return -EFAULT;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700693 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700694
Mona Hossain436b75f2012-11-20 17:10:40 -0800695 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
696 ret = __qseecom_process_incomplete_cmd(data, &resp);
697 if (ret) {
698 pr_err("process_incomplete_cmd failed err: %d\n",
699 ret);
700 if (!IS_ERR_OR_NULL(ihandle))
701 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800702 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800703 return ret;
704 }
705 }
706
707 if (resp.result != QSEOS_RESULT_SUCCESS) {
708 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700709 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -0800710 if (!IS_ERR_OR_NULL(ihandle))
711 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800712 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800713 return -EFAULT;
714 }
715
716 app_id = resp.data;
717
718 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
719 if (!entry) {
720 pr_err("kmalloc failed\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800721 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800722 return -ENOMEM;
723 }
724 entry->app_id = app_id;
725 entry->ref_cnt = 1;
726
727 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700728 if (!IS_ERR_OR_NULL(ihandle))
729 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700730
Mona Hossain436b75f2012-11-20 17:10:40 -0800731 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
732 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
733 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
734 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700735
Mona Hossain436b75f2012-11-20 17:10:40 -0800736 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -0700737 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800738 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800739 data->client.app_id = app_id;
740 load_img_req.app_id = app_id;
741 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
742 pr_err("copy_to_user failed\n");
743 kzfree(entry);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800744 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800745 return -EFAULT;
746 }
Mona Hossain04d3fac2012-12-03 10:10:37 -0800747 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800748 return 0;
749}
750
751static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
752{
753 wake_up_all(&qseecom.send_resp_wq);
754 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700755 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800756 atomic_read(&data->ioctl_count) <= 1)) {
757 pr_err("Interrupted from abort\n");
758 return -ERESTARTSYS;
759 break;
760 }
761 }
762 /* Set unload app */
763 return 1;
764}
765
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800766static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
767{
768 int ret = 0;
769 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
770 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
771 ion_free(qseecom.ion_clnt, data->client.ihandle);
772 data->client.ihandle = NULL;
773 }
774 return ret;
775}
776
Mona Hossain2892b6b2012-02-17 13:53:11 -0800777static int qseecom_unload_app(struct qseecom_dev_handle *data)
778{
779 unsigned long flags;
780 int ret = 0;
781 struct qseecom_command_scm_resp resp;
782 struct qseecom_registered_app_list *ptr_app;
Mona Hossain340dba82012-08-07 19:54:46 -0700783 bool unload = false;
784 bool found_app = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800785
Mona Hossain1fb538f2012-08-30 16:19:38 -0700786 if ((qseecom.qseos_version == QSEOS_VERSION_14) &&
787 (data->client.app_id > 0)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800788 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
789 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
790 list) {
791 if (ptr_app->app_id == data->client.app_id) {
Mona Hossain340dba82012-08-07 19:54:46 -0700792 found_app = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800793 if (ptr_app->ref_cnt == 1) {
Mona Hossain340dba82012-08-07 19:54:46 -0700794 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800795 break;
796 } else {
797 ptr_app->ref_cnt--;
Mona Hossain1fb538f2012-08-30 16:19:38 -0700798 pr_warn("Can't unload app(%d) inuse\n",
Mona Hossaina5f1aab2012-03-29 10:18:07 -0700799 ptr_app->app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800800 break;
801 }
802 }
803 }
804 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
805 flags);
Mona Hossain1fb538f2012-08-30 16:19:38 -0700806 if (found_app == false) {
807 pr_err("Cannot find app with id = %d\n",
808 data->client.app_id);
809 return -EINVAL;
810 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800811 }
812
813 if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
814 struct qseecom_unload_app_ireq req;
815
Mona Hossain340dba82012-08-07 19:54:46 -0700816 __qseecom_cleanup_app(data);
817 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
818 list_del(&ptr_app->list);
819 kzfree(ptr_app);
820 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
821 flags);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800822 /* Populate the structure for sending scm call to load image */
823 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
824 req.app_id = data->client.app_id;
825
826 /* SCM_CALL to unload the app */
827 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
828 sizeof(struct qseecom_unload_app_ireq),
829 &resp, sizeof(resp));
830 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -0700831 pr_err("scm_call to unload app (id = %d) failed\n",
832 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800833 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700834 } else {
835 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800836 }
837 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
838 ret = __qseecom_process_incomplete_cmd(data, &resp);
839 if (ret) {
840 pr_err("process_incomplete_cmd fail err: %d\n",
841 ret);
842 return ret;
843 }
844 }
845 }
846
847 if (qseecom.qseos_version == QSEOS_VERSION_13) {
848 data->abort = 1;
849 wake_up_all(&qseecom.send_resp_wq);
850 while (atomic_read(&data->ioctl_count) > 0) {
Mona Hossainacea1022012-04-09 13:37:27 -0700851 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800852 atomic_read(&data->ioctl_count) <= 0)) {
853 pr_err("Interrupted from abort\n");
854 ret = -ERESTARTSYS;
855 break;
856 }
857 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800858 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800859 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800860 data->released = true;
861 return ret;
862}
863
864static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
865 uint32_t virt)
866{
867 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
868}
869
870static int __qseecom_send_cmd_legacy(struct qseecom_dev_handle *data,
871 struct qseecom_send_cmd_req *req)
872{
873 int ret = 0;
874 unsigned long flags;
875 u32 reqd_len_sb_in = 0;
876 struct qseecom_command cmd;
877 struct qseecom_response resp;
878
879
880 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
881 pr_err("cmd buffer or response buffer is null\n");
882 return -EINVAL;
883 }
884
885 if (req->cmd_req_len <= 0 ||
886 req->resp_len <= 0 ||
887 req->cmd_req_len > data->client.sb_length ||
888 req->resp_len > data->client.sb_length) {
889 pr_err("cmd buffer length or "
890 "response buffer length not valid\n");
891 return -EINVAL;
892 }
893
894 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
895 if (reqd_len_sb_in > data->client.sb_length) {
896 pr_debug("Not enough memory to fit cmd_buf and "
897 "resp_buf. Required: %u, Available: %u\n",
898 reqd_len_sb_in, data->client.sb_length);
899 return -ENOMEM;
900 }
901 cmd.cmd_type = TZ_SCHED_CMD_NEW;
902 cmd.sb_in_cmd_addr = (u8 *) data->client.sb_phys;
903 cmd.sb_in_cmd_len = req->cmd_req_len;
904
905 resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
906 resp.sb_in_rsp_addr = (u8 *)data->client.sb_phys + req->cmd_req_len;
907 resp.sb_in_rsp_len = req->resp_len;
908
909 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
910 sizeof(cmd), &resp, sizeof(resp));
911
912 if (ret) {
913 pr_err("qseecom_scm_call_legacy failed with err: %d\n", ret);
914 return ret;
915 }
916
917 while (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
918 /*
919 * If cmd is incomplete, get the callback cmd out from SB out
920 * and put it on the list
921 */
922 struct qseecom_registered_listener_list *ptr_svc = NULL;
923 /*
924 * We don't know which service can handle the command. so we
925 * wake up all blocking services and let them figure out if
926 * they can handle the given command.
927 */
928 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
929 flags);
930 list_for_each_entry(ptr_svc,
931 &qseecom.registered_listener_list_head, list) {
932 ptr_svc->rcv_req_flag = 1;
933 wake_up_interruptible(&ptr_svc->rcv_req_wq);
934 }
935 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
936 flags);
937
938 pr_debug("waking up rcv_req_wq and "
939 "waiting for send_resp_wq\n");
Mona Hossainacea1022012-04-09 13:37:27 -0700940 if (wait_event_freezable(qseecom.send_resp_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800941 __qseecom_listener_has_sent_rsp(data))) {
942 pr_warning("qseecom Interrupted: exiting send_cmd loop\n");
943 return -ERESTARTSYS;
944 }
945
946 if (data->abort) {
947 pr_err("Aborting driver\n");
948 return -ENODEV;
949 }
950 qseecom.send_resp_flag = 0;
951 cmd.cmd_type = TZ_SCHED_CMD_PENDING;
952 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
953 sizeof(cmd), &resp, sizeof(resp));
954 if (ret) {
955 pr_err("qseecom_scm_call failed with err: %d\n", ret);
956 return ret;
957 }
958 }
959 return ret;
960}
961
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800962int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
963 struct qseecom_send_svc_cmd_req *req_ptr,
964 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
965{
966 int ret = 0;
967 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
968 pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
969 req_ptr, send_svc_ireq_ptr);
970 return -EINVAL;
971 }
972 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
973 send_svc_ireq_ptr->key_type =
974 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type;
975 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
976 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
977 (uint32_t)req_ptr->resp_buf));
978 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
979
980 pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
981 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
982 return ret;
983}
984
985static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
986 void __user *argp)
987{
988 int ret = 0;
989 struct qseecom_client_send_service_ireq send_svc_ireq;
990 struct qseecom_command_scm_resp resp;
991 struct qseecom_send_svc_cmd_req req;
992 /*struct qseecom_command_scm_resp resp;*/
993
994 if (__copy_from_user(&req,
995 (void __user *)argp,
996 sizeof(req))) {
997 pr_err("copy_from_user failed\n");
998 return -EFAULT;
999 }
1000
1001 if (req.resp_buf == NULL) {
1002 pr_err("cmd buffer or response buffer is null\n");
1003 return -EINVAL;
1004 }
1005
1006 data->type = QSEECOM_SECURE_SERVICE;
1007
1008 switch (req.cmd_id) {
1009 case QSEE_RPMB_PROVISION_KEY_COMMAND:
1010 case QSEE_RPMB_ERASE_COMMAND:
1011 if (__qseecom_process_rpmb_svc_cmd(data, &req,
1012 &send_svc_ireq))
1013 return -EINVAL;
1014 break;
1015 default:
1016 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
1017 return -EINVAL;
1018 }
1019
1020 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
1021 sizeof(send_svc_ireq),
1022 &resp, sizeof(resp));
1023 if (ret) {
1024 pr_err("qseecom_scm_call failed with err: %d\n", ret);
1025 return ret;
1026 }
1027
1028 switch (resp.result) {
1029 case QSEOS_RESULT_SUCCESS:
1030 break;
1031 case QSEOS_RESULT_INCOMPLETE:
1032 pr_err("qseos_result_incomplete\n");
1033 ret = __qseecom_process_incomplete_cmd(data, &resp);
1034 if (ret) {
1035 pr_err("process_incomplete_cmd fail: err: %d\n",
1036 ret);
1037 }
1038 break;
1039 case QSEOS_RESULT_FAILURE:
1040 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1041 break;
1042 default:
1043 pr_err("Response result %d not supported\n",
1044 resp.result);
1045 ret = -EINVAL;
1046 break;
1047 }
1048 return ret;
1049
1050}
1051
Mona Hossain2892b6b2012-02-17 13:53:11 -08001052static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1053 struct qseecom_send_cmd_req *req)
1054{
1055 int ret = 0;
1056 u32 reqd_len_sb_in = 0;
1057 struct qseecom_client_send_data_ireq send_data_req;
1058 struct qseecom_command_scm_resp resp;
1059
1060 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
1061 pr_err("cmd buffer or response buffer is null\n");
1062 return -EINVAL;
1063 }
1064
1065 if (req->cmd_req_len <= 0 ||
1066 req->resp_len <= 0 ||
1067 req->cmd_req_len > data->client.sb_length ||
1068 req->resp_len > data->client.sb_length) {
1069 pr_err("cmd buffer length or "
1070 "response buffer length not valid\n");
1071 return -EINVAL;
1072 }
1073
1074 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
1075 if (reqd_len_sb_in > data->client.sb_length) {
1076 pr_debug("Not enough memory to fit cmd_buf and "
1077 "resp_buf. Required: %u, Available: %u\n",
1078 reqd_len_sb_in, data->client.sb_length);
1079 return -ENOMEM;
1080 }
1081
1082 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1083 send_data_req.app_id = data->client.app_id;
1084 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1085 (uint32_t)req->cmd_req_buf));
1086 send_data_req.req_len = req->cmd_req_len;
1087 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1088 (uint32_t)req->resp_buf));
1089 send_data_req.rsp_len = req->resp_len;
1090
1091 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1092 sizeof(send_data_req),
1093 &resp, sizeof(resp));
1094 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001095 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1096 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001097 return ret;
1098 }
1099
1100 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1101 ret = __qseecom_process_incomplete_cmd(data, &resp);
1102 if (ret) {
1103 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1104 return ret;
1105 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001106 } else {
1107 if (resp.result != QSEOS_RESULT_SUCCESS) {
1108 pr_err("Response result %d not supported\n",
1109 resp.result);
1110 ret = -EINVAL;
1111 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001112 }
1113 return ret;
1114}
1115
1116
1117static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1118{
1119 int ret = 0;
1120 struct qseecom_send_cmd_req req;
1121
1122 ret = copy_from_user(&req, argp, sizeof(req));
1123 if (ret) {
1124 pr_err("copy_from_user failed\n");
1125 return ret;
1126 }
1127 if (qseecom.qseos_version == QSEOS_VERSION_14)
1128 ret = __qseecom_send_cmd(data, &req);
1129 else
1130 ret = __qseecom_send_cmd_legacy(data, &req);
1131 if (ret)
1132 return ret;
1133
1134 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1135 req.resp_len, req.resp_buf);
1136 return ret;
1137}
1138
1139static int __qseecom_send_cmd_req_clean_up(
1140 struct qseecom_send_modfd_cmd_req *req)
1141{
1142 char *field;
1143 uint32_t *update;
1144 int ret = 0;
1145 int i = 0;
1146
1147 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossaina5f1aab2012-03-29 10:18:07 -07001148 if (req->ifd_data[i].fd > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001149 field = (char *)req->cmd_req_buf +
1150 req->ifd_data[i].cmd_buf_offset;
1151 update = (uint32_t *) field;
1152 *update = 0;
1153 }
1154 }
1155 return ret;
1156}
1157
1158static int __qseecom_update_with_phy_addr(
1159 struct qseecom_send_modfd_cmd_req *req)
1160{
1161 struct ion_handle *ihandle;
1162 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001163 int ret = 0;
1164 int i = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001165
1166 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001167 struct sg_table *sg_ptr = NULL;
Mona Hossaina5f1aab2012-03-29 10:18:07 -07001168 if (req->ifd_data[i].fd > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001169 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08001170 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001171 req->ifd_data[i].fd);
1172 if (IS_ERR_OR_NULL(ihandle)) {
1173 pr_err("Ion client can't retrieve the handle\n");
1174 return -ENOMEM;
1175 }
1176 field = (char *) req->cmd_req_buf +
1177 req->ifd_data[i].cmd_buf_offset;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001178
1179 /* Populate the cmd data structure with the phys_addr */
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001180 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1181 if (sg_ptr == NULL) {
1182 pr_err("IOn client could not retrieve sg table\n");
1183 goto err;
1184 }
1185 if (sg_ptr->nents == 0) {
1186 pr_err("Num of scattered entries is 0\n");
1187 goto err;
1188 }
1189 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1190 pr_err("Num of scattered entries");
1191 pr_err(" (%d) is greater than max supported %d\n",
1192 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1193 goto err;
1194 }
1195 if (sg_ptr->nents == 1) {
1196 uint32_t *update;
1197 update = (uint32_t *) field;
1198 *update = (uint32_t)sg_dma_address(sg_ptr->sgl);
1199 } else {
1200 struct qseecom_sg_entry *update;
1201 struct scatterlist *sg;
1202 int j = 0;
1203 update = (struct qseecom_sg_entry *) field;
1204 sg = sg_ptr->sgl;
1205 for (j = 0; j < sg_ptr->nents; j++) {
1206 update->phys_addr = (uint32_t)
1207 sg_dma_address(sg);
1208 update->len = (uint32_t)sg->length;
1209 update++;
1210 sg = sg_next(sg);
1211 }
1212 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001213 /* Deallocate the handle */
1214 if (!IS_ERR_OR_NULL(ihandle))
1215 ion_free(qseecom.ion_clnt, ihandle);
1216 }
1217 }
1218 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001219err:
1220 if (!IS_ERR_OR_NULL(ihandle))
1221 ion_free(qseecom.ion_clnt, ihandle);
1222 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001223}
1224
1225static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1226 void __user *argp)
1227{
1228 int ret = 0;
1229 struct qseecom_send_modfd_cmd_req req;
1230 struct qseecom_send_cmd_req send_cmd_req;
1231
1232 ret = copy_from_user(&req, argp, sizeof(req));
1233 if (ret) {
1234 pr_err("copy_from_user failed\n");
1235 return ret;
1236 }
1237 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1238 send_cmd_req.cmd_req_len = req.cmd_req_len;
1239 send_cmd_req.resp_buf = req.resp_buf;
1240 send_cmd_req.resp_len = req.resp_len;
1241
1242 ret = __qseecom_update_with_phy_addr(&req);
1243 if (ret)
1244 return ret;
1245 if (qseecom.qseos_version == QSEOS_VERSION_14)
1246 ret = __qseecom_send_cmd(data, &send_cmd_req);
1247 else
1248 ret = __qseecom_send_cmd_legacy(data, &send_cmd_req);
1249 __qseecom_send_cmd_req_clean_up(&req);
1250
1251 if (ret)
1252 return ret;
1253
1254 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1255 req.resp_len, req.resp_buf);
1256 return ret;
1257}
1258
1259static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1260 struct qseecom_registered_listener_list *svc)
1261{
1262 int ret;
1263 ret = (svc->rcv_req_flag != 0);
1264 return ret || data->abort;
1265}
1266
1267static int qseecom_receive_req(struct qseecom_dev_handle *data)
1268{
1269 int ret = 0;
1270 struct qseecom_registered_listener_list *this_lstnr;
1271
1272 this_lstnr = __qseecom_find_svc(data->listener.id);
1273 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001274 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001275 __qseecom_listener_has_rcvd_req(data,
1276 this_lstnr))) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001277 pr_warning("Interrupted: exiting Listener Service = %d\n",
1278 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001279 /* woken up for different reason */
1280 return -ERESTARTSYS;
1281 }
1282
1283 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001284 pr_err("Aborting Listener Service = %d\n",
1285 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001286 return -ENODEV;
1287 }
1288 this_lstnr->rcv_req_flag = 0;
1289 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1290 if (*((uint32_t *)this_lstnr->sb_virt) != 0)
1291 break;
1292 } else {
1293 break;
1294 }
1295 }
1296 return ret;
1297}
1298
Mona Hossaind44a3842012-10-15 09:41:35 -07001299static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1300{
1301 struct elf32_hdr *ehdr;
1302
1303 if (fw_entry->size < sizeof(*ehdr)) {
1304 pr_err("%s: Not big enough to be an elf header\n",
1305 qseecom.pdev->init_name);
1306 return false;
1307 }
1308 ehdr = (struct elf32_hdr *)fw_entry->data;
1309 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1310 pr_err("%s: Not an elf header\n",
1311 qseecom.pdev->init_name);
1312 return false;
1313 }
1314
1315 if (ehdr->e_phnum == 0) {
1316 pr_err("%s: No loadable segments\n",
1317 qseecom.pdev->init_name);
1318 return false;
1319 }
1320 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1321 sizeof(struct elf32_hdr) > fw_entry->size) {
1322 pr_err("%s: Program headers not within mdt\n",
1323 qseecom.pdev->init_name);
1324 return false;
1325 }
1326 return true;
1327}
1328
1329static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1330{
1331 int ret = -1;
1332 int i = 0, rc = 0;
1333 const struct firmware *fw_entry = NULL;
1334 struct elf32_phdr *phdr;
1335 char fw_name[MAX_APP_NAME_SIZE];
1336 struct elf32_hdr *ehdr;
1337 int num_images = 0;
1338
1339 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1340 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1341 if (rc) {
1342 pr_err("error with request_firmware\n");
1343 ret = -EIO;
1344 goto err;
1345 }
1346 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1347 ret = -EIO;
1348 goto err;
1349 }
1350 *fw_size = fw_entry->size;
1351 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1352 ehdr = (struct elf32_hdr *)fw_entry->data;
1353 num_images = ehdr->e_phnum;
1354 release_firmware(fw_entry);
1355 for (i = 0; i < num_images; i++, phdr++) {
1356 memset(fw_name, 0, sizeof(fw_name));
1357 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1358 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1359 if (ret)
1360 goto err;
1361 *fw_size += fw_entry->size;
1362 release_firmware(fw_entry);
1363 }
1364 return ret;
1365err:
1366 if (fw_entry)
1367 release_firmware(fw_entry);
1368 *fw_size = 0;
1369 return ret;
1370}
1371
1372static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1373 struct qseecom_load_app_ireq *load_req)
1374{
1375 int ret = -1;
1376 int i = 0, rc = 0;
1377 const struct firmware *fw_entry = NULL;
1378 char fw_name[MAX_APP_NAME_SIZE];
1379 u8 *img_data_ptr = img_data;
1380 struct elf32_hdr *ehdr;
1381 int num_images = 0;
1382
1383 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1384 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1385 if (rc) {
1386 ret = -EIO;
1387 goto err;
1388 }
1389 load_req->img_len = fw_entry->size;
1390 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1391 img_data_ptr = img_data_ptr + fw_entry->size;
1392 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1393 ehdr = (struct elf32_hdr *)fw_entry->data;
1394 num_images = ehdr->e_phnum;
1395 release_firmware(fw_entry);
1396 for (i = 0; i < num_images; i++) {
1397 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1398 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1399 if (ret) {
1400 pr_err("Failed to locate blob %s\n", fw_name);
1401 goto err;
1402 }
1403 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1404 img_data_ptr = img_data_ptr + fw_entry->size;
1405 load_req->img_len += fw_entry->size;
1406 release_firmware(fw_entry);
1407 }
1408 load_req->phy_addr = virt_to_phys(img_data);
1409 return ret;
1410err:
1411 release_firmware(fw_entry);
1412 return ret;
1413}
1414
1415static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1416{
1417 int ret = -1;
1418 uint32_t fw_size = 0;
1419 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1420 struct qseecom_command_scm_resp resp;
1421 u8 *img_data = NULL;
1422
1423 if (__qseecom_get_fw_size(appname, &fw_size))
1424 return -EIO;
1425
1426 img_data = kzalloc(fw_size, GFP_KERNEL);
1427 if (!img_data) {
1428 pr_err("Failied to allocate memory for copying image data\n");
1429 return -ENOMEM;
1430 }
1431 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1432 if (ret) {
1433 kzfree(img_data);
1434 return -EIO;
1435 }
1436
1437 /* Populate the remaining parameters */
1438 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1439 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001440 ret = qsee_vote_for_clock(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001441 if (ret) {
1442 kzfree(img_data);
1443 pr_warning("Unable to vote for SFPB clock");
Mona Hossain60f9fb02012-11-05 13:51:50 -08001444 return -EIO;
1445 }
1446
Mona Hossaind44a3842012-10-15 09:41:35 -07001447 /* SCM_CALL to load the image */
1448 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1449 sizeof(struct qseecom_load_app_ireq),
1450 &resp, sizeof(resp));
1451 kzfree(img_data);
1452 if (ret) {
1453 pr_err("scm_call to load failed : ret %d\n", ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001454 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001455 return -EIO;
1456 }
1457
1458 switch (resp.result) {
1459 case QSEOS_RESULT_SUCCESS:
1460 ret = resp.data;
1461 break;
1462 case QSEOS_RESULT_INCOMPLETE:
1463 ret = __qseecom_process_incomplete_cmd(data, &resp);
1464 if (ret)
1465 pr_err("process_incomplete_cmd FAILED\n");
1466 else
1467 ret = resp.data;
1468 break;
1469 case QSEOS_RESULT_FAILURE:
1470 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1471 break;
1472 default:
1473 pr_err("scm call return unknown response %d\n", resp.result);
1474 ret = -EINVAL;
1475 break;
1476 }
Mona Hossain04d3fac2012-12-03 10:10:37 -08001477 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001478
Mona Hossaind44a3842012-10-15 09:41:35 -07001479 return ret;
1480}
1481
Mona Hossain9498f5e2013-01-23 18:08:45 -08001482static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001483{
1484 int32_t ret = 0;
1485 uint32_t fw_size = 0;
1486 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1487 struct qseecom_command_scm_resp resp;
1488 u8 *img_data = NULL;
1489
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001490 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001491 return -EIO;
1492
1493 img_data = kzalloc(fw_size, GFP_KERNEL);
1494 if (!img_data) {
1495 pr_err("Mem allocation for lib image data failed\n");
1496 return -ENOMEM;
1497 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001498 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001499 if (ret) {
1500 kzfree(img_data);
1501 return -EIO;
1502 }
1503 /* Populate the remaining parameters */
1504 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Mona Hossain6311d572013-03-01 15:54:02 -08001505 /* Vote for the SFPB clock */
1506 ret = qsee_vote_for_clock(data, CLK_SFPB);
1507 if (ret) {
1508 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
1509 kzfree(img_data);
1510 return -EIO;
1511 }
1512
Mona Hossain05c73562012-10-29 17:49:01 -07001513 /* SCM_CALL to load the image */
1514 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1515 sizeof(struct qseecom_load_lib_image_ireq),
1516 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001517 if (ret) {
1518 pr_err("scm_call to load failed : ret %d\n", ret);
1519 ret = -EIO;
1520 } else {
1521 switch (resp.result) {
1522 case QSEOS_RESULT_SUCCESS:
1523 break;
1524 case QSEOS_RESULT_FAILURE:
1525 pr_err("scm call failed w/response result%d\n",
1526 resp.result);
1527 ret = -EINVAL;
1528 break;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001529 case QSEOS_RESULT_INCOMPLETE:
1530 ret = __qseecom_process_incomplete_cmd(data, &resp);
1531 if (ret)
1532 pr_err("process_incomplete_cmd failed err: %d\n",
1533 ret);
1534 break;
Mona Hossain05c73562012-10-29 17:49:01 -07001535 default:
1536 pr_err("scm call return unknown response %d\n",
1537 resp.result);
1538 ret = -EINVAL;
1539 break;
1540 }
1541 }
Hariprasad Dhalinarasimha1a81ca32013-01-31 18:32:32 -08001542 kzfree(img_data);
Mona Hossain6311d572013-03-01 15:54:02 -08001543 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain05c73562012-10-29 17:49:01 -07001544 return ret;
1545}
1546
1547static int qseecom_unload_commonlib_image(void)
1548{
1549 int ret = -EINVAL;
1550 struct qseecom_unload_lib_image_ireq unload_req = {0};
1551 struct qseecom_command_scm_resp resp;
1552
1553 /* Populate the remaining parameters */
1554 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1555 /* SCM_CALL to load the image */
1556 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1557 sizeof(struct qseecom_unload_lib_image_ireq),
1558 &resp, sizeof(resp));
1559 if (ret) {
1560 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1561 ret = -EIO;
1562 } else {
1563 switch (resp.result) {
1564 case QSEOS_RESULT_SUCCESS:
1565 break;
1566 case QSEOS_RESULT_FAILURE:
1567 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1568 break;
1569 default:
1570 pr_err("scm call return unknown response %d\n",
1571 resp.result);
1572 ret = -EINVAL;
1573 break;
1574 }
1575 }
1576 return ret;
1577}
1578
Mona Hossaind44a3842012-10-15 09:41:35 -07001579int qseecom_start_app(struct qseecom_handle **handle,
1580 char *app_name, uint32_t size)
1581{
Mona Hossain05c73562012-10-29 17:49:01 -07001582 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07001583 unsigned long flags = 0;
1584 struct qseecom_dev_handle *data = NULL;
1585 struct qseecom_check_app_ireq app_ireq;
1586 struct qseecom_registered_app_list *entry = NULL;
1587 struct qseecom_registered_kclient_list *kclient_entry = NULL;
1588 bool found_app = false;
1589 uint32_t len;
1590 ion_phys_addr_t pa;
1591
1592 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1593 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1594 return -EINVAL;
1595 }
1596
Mona Hossain823f9882012-11-23 14:42:20 -08001597 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
1598 if (!(*handle)) {
1599 pr_err("failed to allocate memory for kernel client handle\n");
1600 return -ENOMEM;
1601 }
1602
Mona Hossaind44a3842012-10-15 09:41:35 -07001603 data = kzalloc(sizeof(*data), GFP_KERNEL);
1604 if (!data) {
1605 pr_err("kmalloc failed\n");
1606 if (ret == 0) {
1607 kfree(*handle);
1608 *handle = NULL;
1609 }
1610 return -ENOMEM;
1611 }
1612 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001613 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07001614 data->released = false;
1615 data->client.app_id = ret;
1616 data->client.sb_length = size;
1617 data->client.user_virt_sb_base = 0;
1618 data->client.ihandle = NULL;
1619
1620 init_waitqueue_head(&data->abort_wq);
1621 atomic_set(&data->ioctl_count, 0);
1622
1623 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
1624 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1625 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1626 pr_err("Ion client could not retrieve the handle\n");
1627 kfree(data);
1628 kfree(*handle);
1629 *handle = NULL;
1630 return -EINVAL;
1631 }
1632
Mona Hossain9498f5e2013-01-23 18:08:45 -08001633 if (qseecom.qsee_version > QSEEE_VERSION_00) {
1634 mutex_lock(&app_access_lock);
1635 if (qseecom.commonlib_loaded == false) {
1636 ret = qseecom_load_commonlib_image(data);
1637 if (ret == 0)
1638 qseecom.commonlib_loaded = true;
1639 }
1640 mutex_unlock(&app_access_lock);
1641 }
1642
1643 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001644 pr_err("Failed to load commonlib image\n");
Mona Hossain9498f5e2013-01-23 18:08:45 -08001645 kfree(data);
1646 kfree(*handle);
1647 *handle = NULL;
1648 return -EIO;
1649 }
1650
1651 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
1652 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
1653 ret = __qseecom_check_app_exists(app_ireq);
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001654 if (ret < 0) {
1655 kzfree(data);
1656 kfree(*handle);
1657 *handle = NULL;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001658 return -EINVAL;
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001659 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001660
Mona Hossaind44a3842012-10-15 09:41:35 -07001661 if (ret > 0) {
1662 pr_warn("App id %d for [%s] app exists\n", ret,
1663 (char *)app_ireq.app_name);
1664 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1665 list_for_each_entry(entry,
1666 &qseecom.registered_app_list_head, list){
1667 if (entry->app_id == ret) {
1668 entry->ref_cnt++;
1669 found_app = true;
1670 break;
1671 }
1672 }
1673 spin_unlock_irqrestore(
1674 &qseecom.registered_app_list_lock, flags);
1675 if (!found_app)
1676 pr_warn("App_id %d [%s] was loaded but not registered\n",
1677 ret, (char *)app_ireq.app_name);
1678 } else {
1679 /* load the app and get the app_id */
1680 pr_debug("%s: Loading app for the first time'\n",
1681 qseecom.pdev->init_name);
1682 mutex_lock(&app_access_lock);
1683 ret = __qseecom_load_fw(data, app_name);
1684 mutex_unlock(&app_access_lock);
1685
1686 if (ret < 0) {
1687 kfree(*handle);
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001688 kfree(data);
Mona Hossaind44a3842012-10-15 09:41:35 -07001689 *handle = NULL;
1690 return ret;
1691 }
1692 data->client.app_id = ret;
1693 }
1694 if (!found_app) {
1695 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1696 if (!entry) {
1697 pr_err("kmalloc failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001698 kfree(data);
1699 kfree(*handle);
1700 *handle = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07001701 return -ENOMEM;
1702 }
1703 entry->app_id = ret;
1704 entry->ref_cnt = 1;
1705
1706 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1707 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1708 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1709 flags);
1710 }
1711
1712 /* Get the physical address of the ION BUF */
1713 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
1714 /* Populate the structure for sending scm call to load image */
1715 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
1716 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08001717 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07001718 data->client.sb_phys = pa;
1719 (*handle)->dev = (void *)data;
1720 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
1721 (*handle)->sbuf_len = data->client.sb_length;
1722
1723 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
1724 if (!kclient_entry) {
1725 pr_err("kmalloc failed\n");
1726 return -ENOMEM;
1727 }
1728 kclient_entry->handle = *handle;
1729
1730 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1731 list_add_tail(&kclient_entry->list,
1732 &qseecom.registered_kclient_list_head);
1733 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1734
1735 return 0;
1736}
1737EXPORT_SYMBOL(qseecom_start_app);
1738
1739int qseecom_shutdown_app(struct qseecom_handle **handle)
1740{
1741 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08001742 struct qseecom_dev_handle *data;
1743
Mona Hossaind44a3842012-10-15 09:41:35 -07001744 struct qseecom_registered_kclient_list *kclient = NULL;
1745 unsigned long flags = 0;
1746 bool found_handle = false;
1747
1748 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1749 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1750 return -EINVAL;
1751 }
Mona Hossain33824022013-02-25 09:32:33 -08001752 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07001753 pr_err("Handle is not initialized\n");
1754 return -EINVAL;
1755 }
Mona Hossain33824022013-02-25 09:32:33 -08001756 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07001757 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1758 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
1759 list) {
1760 if (kclient->handle == (*handle)) {
1761 list_del(&kclient->list);
1762 found_handle = true;
1763 break;
1764 }
1765 }
1766 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1767 if (!found_handle)
1768 pr_err("Unable to find the handle, exiting\n");
1769 else
1770 ret = qseecom_unload_app(data);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001771 if (data->client.fast_load_enabled == true)
1772 qsee_disable_clock_vote(data, CLK_SFPB);
1773 if (data->client.perf_enabled == true)
1774 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001775 if (ret == 0) {
1776 kzfree(data);
1777 kzfree(*handle);
1778 kzfree(kclient);
1779 *handle = NULL;
1780 }
1781 return ret;
1782}
1783EXPORT_SYMBOL(qseecom_shutdown_app);
1784
1785int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
1786 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
1787{
1788 int ret = 0;
1789 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
1790 struct qseecom_dev_handle *data;
1791
1792 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1793 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1794 return -EINVAL;
1795 }
1796
1797 if (handle == NULL) {
1798 pr_err("Handle is not initialized\n");
1799 return -EINVAL;
1800 }
1801 data = handle->dev;
1802
1803 req.cmd_req_len = sbuf_len;
1804 req.resp_len = rbuf_len;
1805 req.cmd_req_buf = send_buf;
1806 req.resp_buf = resp_buf;
1807
1808 mutex_lock(&app_access_lock);
1809 atomic_inc(&data->ioctl_count);
1810
1811 ret = __qseecom_send_cmd(data, &req);
1812
1813 atomic_dec(&data->ioctl_count);
1814 mutex_unlock(&app_access_lock);
1815
1816 if (ret)
1817 return ret;
1818
1819 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1820 req.resp_len, req.resp_buf);
1821 return ret;
1822}
1823EXPORT_SYMBOL(qseecom_send_command);
1824
Mona Hossain91a8fc92012-11-07 19:58:30 -08001825int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
1826{
Mona Hossainfca6f422013-01-12 13:00:35 -08001827 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001828 if ((handle == NULL) || (handle->dev == NULL)) {
1829 pr_err("No valid kernel client\n");
1830 return -EINVAL;
1831 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001832 if (high) {
1833 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
1834 if (ret)
1835 pr_err("Failed to vote for DFAB clock%d\n", ret);
1836 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
1837 if (ret) {
1838 pr_err("Failed to vote for SFPB clock%d\n", ret);
1839 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
1840 }
1841 } else {
Mona Hossain04d3fac2012-12-03 10:10:37 -08001842 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
Mona Hossainfca6f422013-01-12 13:00:35 -08001843 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
Mona Hossain91a8fc92012-11-07 19:58:30 -08001844 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001845 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001846}
1847EXPORT_SYMBOL(qseecom_set_bandwidth);
1848
Mona Hossain2892b6b2012-02-17 13:53:11 -08001849static int qseecom_send_resp(void)
1850{
1851 qseecom.send_resp_flag = 1;
1852 wake_up_interruptible(&qseecom.send_resp_wq);
1853 return 0;
1854}
1855
1856static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
1857 void __user *argp)
1858{
1859 struct qseecom_qseos_version_req req;
1860
1861 if (copy_from_user(&req, argp, sizeof(req))) {
1862 pr_err("copy_from_user failed");
1863 return -EINVAL;
1864 }
1865 req.qseos_version = qseecom.qseos_version;
1866 if (copy_to_user(argp, &req, sizeof(req))) {
1867 pr_err("copy_to_user failed");
1868 return -EINVAL;
1869 }
1870 return 0;
1871}
1872
Mona Hossain6311d572013-03-01 15:54:02 -08001873static int __qseecom_enable_clk(void)
1874{
1875 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001876 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08001877
Mona Hossain17a4faf2013-03-22 16:40:56 -07001878 qclk = &qseecom.qsee;
Mona Hossain6311d572013-03-01 15:54:02 -08001879 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07001880 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001881 if (rc) {
1882 pr_err("Unable to enable/prepare CE core clk\n");
1883 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001884 }
1885 /* Enable CE clk */
1886 rc = clk_prepare_enable(qclk->ce_clk);
1887 if (rc) {
1888 pr_err("Unable to enable/prepare CE iface clk\n");
1889 goto ce_clk_err;
1890 }
1891 /* Enable AXI clk */
1892 rc = clk_prepare_enable(qclk->ce_bus_clk);
1893 if (rc) {
1894 pr_err("Unable to enable/prepare CE bus clk\n");
1895 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08001896 }
1897 return 0;
1898
1899ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001900 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001901ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001902 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001903err:
1904 return -EIO;
1905}
1906
1907static void __qseecom_disable_clk(void)
1908{
Mona Hossain17a4faf2013-03-22 16:40:56 -07001909 struct qseecom_clk *qclk;
1910
1911 qclk = &qseecom.qsee;
1912 if (qclk->ce_clk != NULL)
1913 clk_disable_unprepare(qclk->ce_clk);
1914 if (qclk->ce_core_clk != NULL)
1915 clk_disable_unprepare(qclk->ce_core_clk);
1916 if (qclk->ce_bus_clk != NULL)
1917 clk_disable_unprepare(qclk->ce_bus_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001918}
1919
Mona Hossain04d3fac2012-12-03 10:10:37 -08001920static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
1921 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001922{
1923 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001924 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001925
Mona Hossain17a4faf2013-03-22 16:40:56 -07001926 qclk = &qseecom.qsee;
1927 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07001928 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001929
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001930 switch (clk_type) {
1931 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001932 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07001933 if (!qseecom.qsee_bw_count) {
1934 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001935 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001936 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08001937 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001938 if (qclk->ce_core_src_clk != NULL)
Mona Hossain6311d572013-03-01 15:54:02 -08001939 ret = __qseecom_enable_clk();
1940 if (!ret) {
1941 ret =
1942 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001943 qseecom.qsee_perf_client, 1);
1944 if ((ret) &&
1945 (qclk->ce_core_src_clk != NULL))
Mona Hossain6311d572013-03-01 15:54:02 -08001946 __qseecom_disable_clk();
1947 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08001948 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001949 if (ret)
1950 pr_err("DFAB Bandwidth req failed (%d)\n",
1951 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001952 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001953 qseecom.qsee_bw_count++;
Mona Hossain04d3fac2012-12-03 10:10:37 -08001954 data->client.perf_enabled = true;
1955 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001956 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001957 qseecom.qsee_bw_count++;
Mona Hossain04d3fac2012-12-03 10:10:37 -08001958 data->client.perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001959 }
1960 mutex_unlock(&qsee_bw_mutex);
1961 break;
1962 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001963 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07001964 if (!qseecom.qsee_sfpb_bw_count) {
1965 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001966 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001967 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08001968 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001969 if (qclk->ce_core_src_clk != NULL)
Mona Hossain6311d572013-03-01 15:54:02 -08001970 ret = __qseecom_enable_clk();
1971 if (!ret) {
1972 ret =
1973 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001974 qseecom.qsee_perf_client, 2);
1975 if ((ret) &&
1976 (qclk->ce_core_src_clk != NULL))
Mona Hossain6311d572013-03-01 15:54:02 -08001977 __qseecom_disable_clk();
1978 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08001979 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001980
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001981 if (ret)
1982 pr_err("SFPB Bandwidth req failed (%d)\n",
1983 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001984 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001985 qseecom.qsee_sfpb_bw_count++;
Mona Hossain04d3fac2012-12-03 10:10:37 -08001986 data->client.fast_load_enabled = true;
1987 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001988 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001989 qseecom.qsee_sfpb_bw_count++;
Mona Hossain04d3fac2012-12-03 10:10:37 -08001990 data->client.fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001991 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001992 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001993 break;
1994 default:
1995 pr_err("Clock type not defined\n");
1996 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001997 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001998 return ret;
1999}
2000
Mona Hossain04d3fac2012-12-03 10:10:37 -08002001static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2002 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002003{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002004 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002005 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002006
Mona Hossain17a4faf2013-03-22 16:40:56 -07002007 qclk = &qseecom.qsee;
2008 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002009 return;
2010
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002011 switch (clk_type) {
2012 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002013 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002014 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002015 pr_err("Client error.Extra call to disable DFAB clk\n");
2016 mutex_unlock(&qsee_bw_mutex);
2017 return;
2018 }
2019
Mona Hossain17a4faf2013-03-22 16:40:56 -07002020 if (qseecom.qsee_bw_count == 1) {
2021 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002022 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002023 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002024 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002025 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002026 qseecom.qsee_perf_client, 0);
2027 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossain6311d572013-03-01 15:54:02 -08002028 __qseecom_disable_clk();
Mona Hossaind39e33b2012-11-05 13:36:40 -08002029 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002030 if (ret)
2031 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002032 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002033 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002034 qseecom.qsee_bw_count--;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002035 data->client.perf_enabled = false;
2036 }
2037 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002038 qseecom.qsee_bw_count--;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002039 data->client.perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002040 }
2041 mutex_unlock(&qsee_bw_mutex);
2042 break;
2043 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002044 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002045 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002046 pr_err("Client error.Extra call to disable SFPB clk\n");
2047 mutex_unlock(&qsee_bw_mutex);
2048 return;
2049 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002050 if (qseecom.qsee_sfpb_bw_count == 1) {
2051 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002052 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002053 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002054 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002055 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002056 qseecom.qsee_perf_client, 0);
2057 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossain6311d572013-03-01 15:54:02 -08002058 __qseecom_disable_clk();
Mona Hossaind39e33b2012-11-05 13:36:40 -08002059 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002060 if (ret)
2061 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002062 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002063 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002064 qseecom.qsee_sfpb_bw_count--;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002065 data->client.fast_load_enabled = false;
2066 }
2067 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002068 qseecom.qsee_sfpb_bw_count--;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002069 data->client.fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002070 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002071 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002072 break;
2073 default:
2074 pr_err("Clock type not defined\n");
2075 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002076 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002077
Mona Hossain2892b6b2012-02-17 13:53:11 -08002078}
2079
Mona Hossain5ab9d772012-04-11 21:00:40 -07002080static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2081 void __user *argp)
2082{
2083 struct ion_handle *ihandle; /* Ion handle */
2084 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002085 int ret;
2086 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002087 ion_phys_addr_t pa = 0;
2088 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002089 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002090 struct qseecom_load_app_ireq load_req;
2091 struct qseecom_command_scm_resp resp;
2092
2093 /* Copy the relevant information needed for loading the image */
2094 if (__copy_from_user(&load_img_req,
2095 (void __user *)argp,
2096 sizeof(struct qseecom_load_img_req))) {
2097 pr_err("copy_from_user failed\n");
2098 return -EFAULT;
2099 }
2100
2101 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002102 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002103 load_img_req.ifd_data_fd);
2104 if (IS_ERR_OR_NULL(ihandle)) {
2105 pr_err("Ion client could not retrieve the handle\n");
2106 return -ENOMEM;
2107 }
2108
2109 /* Get the physical address of the ION BUF */
2110 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
2111
2112 /* Populate the structure for sending scm call to load image */
2113 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
2114 load_req.mdt_len = load_img_req.mdt_len;
2115 load_req.img_len = load_img_req.img_len;
2116 load_req.phy_addr = pa;
2117
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002118 /* SCM_CALL tied to Core0 */
2119 mask = CPU_MASK_CPU0;
2120 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2121 if (set_cpu_ret) {
2122 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2123 set_cpu_ret);
2124 ret = -EFAULT;
2125 goto qseecom_load_external_elf_set_cpu_err;
2126 }
Mona Hossain6311d572013-03-01 15:54:02 -08002127 /* Vote for the SFPB clock */
2128 ret = qsee_vote_for_clock(data, CLK_SFPB);
2129 if (ret) {
2130 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
2131 ret = -EIO;
2132 goto qseecom_load_external_elf_set_cpu_err;
2133 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002134
Mona Hossain5ab9d772012-04-11 21:00:40 -07002135 /* SCM_CALL to load the external elf */
2136 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2137 sizeof(struct qseecom_load_app_ireq),
2138 &resp, sizeof(resp));
2139 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002140 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07002141 ret);
2142 ret = -EFAULT;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002143 goto qseecom_load_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002144 }
2145
2146 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2147 ret = __qseecom_process_incomplete_cmd(data, &resp);
2148 if (ret)
2149 pr_err("process_incomplete_cmd failed err: %d\n",
2150 ret);
2151 } else {
2152 if (resp.result != QSEOS_RESULT_SUCCESS) {
2153 pr_err("scm_call to load image failed resp.result =%d\n",
2154 resp.result);
2155 ret = -EFAULT;
2156 }
2157 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002158
2159qseecom_load_external_elf_scm_err:
2160 /* Restore the CPU mask */
2161 mask = CPU_MASK_ALL;
2162 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2163 if (set_cpu_ret) {
2164 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2165 set_cpu_ret);
2166 ret = -EFAULT;
2167 }
2168
2169qseecom_load_external_elf_set_cpu_err:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002170 /* Deallocate the handle */
2171 if (!IS_ERR_OR_NULL(ihandle))
2172 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain6311d572013-03-01 15:54:02 -08002173 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002174 return ret;
2175}
2176
2177static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2178{
2179 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002180 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002181 struct qseecom_command_scm_resp resp;
2182 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002183 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002184
2185 /* Populate the structure for sending scm call to unload image */
2186 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002187
2188 /* SCM_CALL tied to Core0 */
2189 mask = CPU_MASK_CPU0;
2190 ret = set_cpus_allowed_ptr(current, &mask);
2191 if (ret) {
2192 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2193 ret);
2194 return -EFAULT;
2195 }
2196
Mona Hossain5ab9d772012-04-11 21:00:40 -07002197 /* SCM_CALL to unload the external elf */
2198 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2199 sizeof(struct qseecom_unload_app_ireq),
2200 &resp, sizeof(resp));
2201 if (ret) {
2202 pr_err("scm_call to unload failed : ret %d\n",
2203 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002204 ret = -EFAULT;
2205 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002206 }
2207 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2208 ret = __qseecom_process_incomplete_cmd(data, &resp);
2209 if (ret)
2210 pr_err("process_incomplete_cmd fail err: %d\n",
2211 ret);
2212 } else {
2213 if (resp.result != QSEOS_RESULT_SUCCESS) {
2214 pr_err("scm_call to unload image failed resp.result =%d\n",
2215 resp.result);
2216 ret = -EFAULT;
2217 }
2218 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002219
2220qseecom_unload_external_elf_scm_err:
2221 /* Restore the CPU mask */
2222 mask = CPU_MASK_ALL;
2223 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2224 if (set_cpu_ret) {
2225 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2226 set_cpu_ret);
2227 ret = -EFAULT;
2228 }
2229
Mona Hossain5ab9d772012-04-11 21:00:40 -07002230 return ret;
2231}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002232
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002233static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2234 void __user *argp)
2235{
2236
2237 int32_t ret;
2238 struct qseecom_qseos_app_load_query query_req;
2239 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002240 struct qseecom_registered_app_list *entry = NULL;
2241 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002242
2243 /* Copy the relevant information needed for loading the image */
2244 if (__copy_from_user(&query_req,
2245 (void __user *)argp,
2246 sizeof(struct qseecom_qseos_app_load_query))) {
2247 pr_err("copy_from_user failed\n");
2248 return -EFAULT;
2249 }
2250
2251 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
2252 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2253
2254 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002255
2256 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002257 pr_err(" scm call to check if app is loaded failed");
2258 return ret; /* scm call failed */
2259 } else if (ret > 0) {
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002260 pr_warn("App id %d (%s) already exists\n", ret,
2261 (char *)(req.app_name));
2262 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2263 list_for_each_entry(entry,
2264 &qseecom.registered_app_list_head, list){
2265 if (entry->app_id == ret) {
2266 entry->ref_cnt++;
2267 break;
2268 }
2269 }
2270 spin_unlock_irqrestore(
2271 &qseecom.registered_app_list_lock, flags);
2272 data->client.app_id = ret;
2273 query_req.app_id = ret;
2274
2275 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2276 pr_err("copy_to_user failed\n");
2277 return -EFAULT;
2278 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002279 return -EEXIST; /* app already loaded */
2280 } else {
2281 return 0; /* app not loaded */
2282 }
2283}
2284
Mona Hossain2892b6b2012-02-17 13:53:11 -08002285static long qseecom_ioctl(struct file *file, unsigned cmd,
2286 unsigned long arg)
2287{
2288 int ret = 0;
2289 struct qseecom_dev_handle *data = file->private_data;
2290 void __user *argp = (void __user *) arg;
2291
2292 if (data->abort) {
2293 pr_err("Aborting qseecom driver\n");
2294 return -ENODEV;
2295 }
2296
2297 switch (cmd) {
2298 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
2299 pr_debug("ioctl register_listener_req()\n");
2300 atomic_inc(&data->ioctl_count);
2301 ret = qseecom_register_listener(data, argp);
2302 atomic_dec(&data->ioctl_count);
2303 wake_up_all(&data->abort_wq);
2304 if (ret)
2305 pr_err("failed qseecom_register_listener: %d\n", ret);
2306 break;
2307 }
2308 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
2309 pr_debug("ioctl unregister_listener_req()\n");
2310 atomic_inc(&data->ioctl_count);
2311 ret = qseecom_unregister_listener(data);
2312 atomic_dec(&data->ioctl_count);
2313 wake_up_all(&data->abort_wq);
2314 if (ret)
2315 pr_err("failed qseecom_unregister_listener: %d\n", ret);
2316 break;
2317 }
2318 case QSEECOM_IOCTL_SEND_CMD_REQ: {
2319 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002320 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002321 atomic_inc(&data->ioctl_count);
2322 ret = qseecom_send_cmd(data, argp);
2323 atomic_dec(&data->ioctl_count);
2324 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002325 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002326 if (ret)
2327 pr_err("failed qseecom_send_cmd: %d\n", ret);
2328 break;
2329 }
2330 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
2331 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002332 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002333 atomic_inc(&data->ioctl_count);
2334 ret = qseecom_send_modfd_cmd(data, argp);
2335 atomic_dec(&data->ioctl_count);
2336 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002337 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002338 if (ret)
2339 pr_err("failed qseecom_send_cmd: %d\n", ret);
2340 break;
2341 }
2342 case QSEECOM_IOCTL_RECEIVE_REQ: {
2343 atomic_inc(&data->ioctl_count);
2344 ret = qseecom_receive_req(data);
2345 atomic_dec(&data->ioctl_count);
2346 wake_up_all(&data->abort_wq);
2347 if (ret)
2348 pr_err("failed qseecom_receive_req: %d\n", ret);
2349 break;
2350 }
2351 case QSEECOM_IOCTL_SEND_RESP_REQ: {
2352 atomic_inc(&data->ioctl_count);
2353 ret = qseecom_send_resp();
2354 atomic_dec(&data->ioctl_count);
2355 wake_up_all(&data->abort_wq);
2356 if (ret)
2357 pr_err("failed qseecom_send_resp: %d\n", ret);
2358 break;
2359 }
2360 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
2361 ret = qseecom_set_client_mem_param(data, argp);
2362 if (ret)
2363 pr_err("failed Qqseecom_set_mem_param request: %d\n",
2364 ret);
2365 break;
2366 }
2367 case QSEECOM_IOCTL_LOAD_APP_REQ: {
2368 mutex_lock(&app_access_lock);
2369 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07002370 if (qseecom.qsee_version > QSEEE_VERSION_00) {
2371 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08002372 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07002373 if (ret == 0)
2374 qseecom.commonlib_loaded = true;
2375 }
2376 }
2377 if (ret == 0)
2378 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002379 atomic_dec(&data->ioctl_count);
2380 mutex_unlock(&app_access_lock);
2381 if (ret)
2382 pr_err("failed load_app request: %d\n", ret);
2383 break;
2384 }
2385 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
2386 mutex_lock(&app_access_lock);
2387 atomic_inc(&data->ioctl_count);
2388 ret = qseecom_unload_app(data);
2389 atomic_dec(&data->ioctl_count);
2390 mutex_unlock(&app_access_lock);
2391 if (ret)
2392 pr_err("failed unload_app request: %d\n", ret);
2393 break;
2394 }
2395 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
2396 atomic_inc(&data->ioctl_count);
2397 ret = qseecom_get_qseos_version(data, argp);
2398 if (ret)
2399 pr_err("qseecom_get_qseos_version: %d\n", ret);
2400 atomic_dec(&data->ioctl_count);
2401 break;
2402 }
2403 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
2404 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002405 ret = qsee_vote_for_clock(data, CLK_DFAB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002406 if (ret)
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002407 pr_err("Failed to vote for DFAB clock%d\n", ret);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002408 ret = qsee_vote_for_clock(data, CLK_SFPB);
2409 if (ret)
2410 pr_err("Failed to vote for SFPB clock%d\n", ret);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002411 atomic_dec(&data->ioctl_count);
2412 break;
2413 }
2414 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
2415 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002416 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002417 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002418 atomic_dec(&data->ioctl_count);
2419 break;
2420 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07002421 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
2422 data->released = true;
2423 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2424 pr_err("Loading External elf image unsupported in rev 0x13\n");
2425 ret = -EINVAL;
2426 break;
2427 }
2428 mutex_lock(&app_access_lock);
2429 atomic_inc(&data->ioctl_count);
2430 ret = qseecom_load_external_elf(data, argp);
2431 atomic_dec(&data->ioctl_count);
2432 mutex_unlock(&app_access_lock);
2433 if (ret)
2434 pr_err("failed load_external_elf request: %d\n", ret);
2435 break;
2436 }
2437 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
2438 data->released = true;
2439 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2440 pr_err("Unloading External elf image unsupported in rev 0x13\n");
2441 ret = -EINVAL;
2442 break;
2443 }
2444 mutex_lock(&app_access_lock);
2445 atomic_inc(&data->ioctl_count);
2446 ret = qseecom_unload_external_elf(data);
2447 atomic_dec(&data->ioctl_count);
2448 mutex_unlock(&app_access_lock);
2449 if (ret)
2450 pr_err("failed unload_app request: %d\n", ret);
2451 break;
2452 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002453 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
2454 mutex_lock(&app_access_lock);
2455 atomic_inc(&data->ioctl_count);
2456 ret = qseecom_query_app_loaded(data, argp);
2457 atomic_dec(&data->ioctl_count);
2458 mutex_unlock(&app_access_lock);
2459 break;
2460 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002461 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
2462 if (qseecom.qsee_version < QSEE_VERSION_03) {
2463 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee version %u\n",
2464 qseecom.qsee_version);
2465 return -EINVAL;
2466 }
2467 mutex_lock(&app_access_lock);
2468 atomic_inc(&data->ioctl_count);
2469 ret = qseecom_send_service_cmd(data, argp);
2470 atomic_dec(&data->ioctl_count);
2471 mutex_unlock(&app_access_lock);
2472 break;
2473 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002474 default:
2475 return -EINVAL;
2476 }
2477 return ret;
2478}
2479
2480static int qseecom_open(struct inode *inode, struct file *file)
2481{
2482 int ret = 0;
2483 struct qseecom_dev_handle *data;
2484
2485 data = kzalloc(sizeof(*data), GFP_KERNEL);
2486 if (!data) {
2487 pr_err("kmalloc failed\n");
2488 return -ENOMEM;
2489 }
2490 file->private_data = data;
2491 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002492 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002493 data->released = false;
2494 init_waitqueue_head(&data->abort_wq);
2495 atomic_set(&data->ioctl_count, 0);
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07002496 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2497 int pil_error;
2498 mutex_lock(&pil_access_lock);
2499 if (pil_ref_cnt == 0) {
Stephen Boyd77db8bb2012-06-27 15:15:16 -07002500 pil = subsystem_get("tzapps");
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07002501 if (IS_ERR(pil)) {
2502 pr_err("Playready PIL image load failed\n");
2503 pil_error = PTR_ERR(pil);
2504 pil = NULL;
2505 pr_debug("tzapps image load FAILED\n");
2506 mutex_unlock(&pil_access_lock);
2507 return pil_error;
2508 }
2509 }
2510 pil_ref_cnt++;
2511 mutex_unlock(&pil_access_lock);
2512 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002513 return ret;
2514}
2515
2516static int qseecom_release(struct inode *inode, struct file *file)
2517{
2518 struct qseecom_dev_handle *data = file->private_data;
2519 int ret = 0;
2520
2521 if (data->released == false) {
2522 pr_warn("data->released == false\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002523 switch (data->type) {
2524 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08002525 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002526 break;
2527 case QSEECOM_CLIENT_APP:
Mona Hossain2892b6b2012-02-17 13:53:11 -08002528 ret = qseecom_unload_app(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002529 break;
2530 case QSEECOM_SECURE_SERVICE:
2531 ret = qseecom_unmap_ion_allocated_memory(data);
2532 if (ret) {
2533 pr_err("Close failed\n");
2534 return ret;
2535 }
2536 break;
2537 default:
2538 pr_err("Unsupported clnt_handle_type %d",
2539 data->type);
2540 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002541 }
2542 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002543
Mona Hossain04d3fac2012-12-03 10:10:37 -08002544 if (data->client.fast_load_enabled == true)
2545 qsee_disable_clock_vote(data, CLK_SFPB);
2546 if (data->client.perf_enabled == true)
2547 qsee_disable_clock_vote(data, CLK_DFAB);
2548
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07002549 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2550 mutex_lock(&pil_access_lock);
2551 if (pil_ref_cnt == 1)
Stephen Boyd77db8bb2012-06-27 15:15:16 -07002552 subsystem_put(pil);
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07002553 pil_ref_cnt--;
2554 mutex_unlock(&pil_access_lock);
2555 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002556 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002557
Mona Hossain2892b6b2012-02-17 13:53:11 -08002558 return ret;
2559}
2560
Mona Hossain2892b6b2012-02-17 13:53:11 -08002561static const struct file_operations qseecom_fops = {
2562 .owner = THIS_MODULE,
2563 .unlocked_ioctl = qseecom_ioctl,
2564 .open = qseecom_open,
2565 .release = qseecom_release
2566};
2567
Mona Hossaind39e33b2012-11-05 13:36:40 -08002568static int __qseecom_init_clk(void)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002569{
2570 int rc = 0;
2571 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002572 struct qseecom_clk *qclk;
2573
2574 qclk = &qseecom.qsee;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002575
2576 pdev = qseecom.pdev;
2577 /* Get CE3 src core clk. */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002578
2579 qclk->ce_core_src_clk = clk_get(pdev, "core_clk_src");
2580 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08002581 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002582 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002583 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002584 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002585 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08002586 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002587 }
2588 } else {
2589 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07002590 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002591 }
2592
2593 /* Get CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002594 qclk->ce_core_clk = clk_get(pdev, "core_clk");
2595 if (IS_ERR(qclk->ce_core_clk)) {
2596 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002597 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07002598 if (qclk->ce_core_src_clk != NULL)
2599 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002600 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002601 }
2602
2603 /* Get CE Interface clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002604 qclk->ce_clk = clk_get(pdev, "iface_clk");
2605 if (IS_ERR(qclk->ce_clk)) {
2606 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002607 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07002608 if (qclk->ce_core_src_clk != NULL)
2609 clk_put(qclk->ce_core_src_clk);
2610 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002611 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002612 }
2613
2614 /* Get CE AXI clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002615 qclk->ce_bus_clk = clk_get(pdev, "bus_clk");
2616 if (IS_ERR(qclk->ce_bus_clk)) {
2617 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002618 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07002619 if (qclk->ce_core_src_clk != NULL)
2620 clk_put(qclk->ce_core_src_clk);
2621 clk_put(qclk->ce_core_clk);
2622 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002623 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002624 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002625 return rc;
2626}
2627
Mona Hossaind39e33b2012-11-05 13:36:40 -08002628static void __qseecom_deinit_clk(void)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002629{
Mona Hossain17a4faf2013-03-22 16:40:56 -07002630 struct qseecom_clk *qclk;
2631
2632 qclk = &qseecom.qsee;
2633
2634 if (qclk->ce_clk != NULL) {
2635 clk_put(qclk->ce_clk);
2636 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08002637 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002638 if (qclk->ce_core_clk != NULL) {
2639 clk_put(qclk->ce_core_clk);
2640 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08002641 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002642 if (qclk->ce_bus_clk != NULL) {
2643 clk_put(qclk->ce_bus_clk);
2644 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08002645 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002646 if (qclk->ce_core_src_clk != NULL) {
2647 clk_put(qclk->ce_core_src_clk);
2648 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08002649 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002650}
2651
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002652static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002653{
2654 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08002655 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002656 struct device *class_dev;
2657 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07002658 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002659 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
2660
Mona Hossain17a4faf2013-03-22 16:40:56 -07002661 qseecom.qsee_bw_count = 0;
2662 qseecom.qsee_perf_client = 0;
2663 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08002664
Mona Hossain17a4faf2013-03-22 16:40:56 -07002665 qseecom.qsee.ce_core_clk = NULL;
2666 qseecom.qsee.ce_clk = NULL;
2667 qseecom.qsee.ce_core_src_clk = NULL;
2668 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002669
Mona Hossain2892b6b2012-02-17 13:53:11 -08002670 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
2671 if (rc < 0) {
2672 pr_err("alloc_chrdev_region failed %d\n", rc);
2673 return rc;
2674 }
2675
2676 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
2677 if (IS_ERR(driver_class)) {
2678 rc = -ENOMEM;
2679 pr_err("class_create failed %d\n", rc);
2680 goto unregister_chrdev_region;
2681 }
2682
2683 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
2684 QSEECOM_DEV);
2685 if (!class_dev) {
2686 pr_err("class_device_create failed %d\n", rc);
2687 rc = -ENOMEM;
2688 goto class_destroy;
2689 }
2690
2691 cdev_init(&qseecom_cdev, &qseecom_fops);
2692 qseecom_cdev.owner = THIS_MODULE;
2693
2694 rc = cdev_add(&qseecom_cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
2695 if (rc < 0) {
2696 pr_err("cdev_add failed %d\n", rc);
2697 goto err;
2698 }
2699
2700 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
2701 spin_lock_init(&qseecom.registered_listener_list_lock);
2702 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
2703 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07002704 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
2705 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002706 init_waitqueue_head(&qseecom.send_resp_wq);
2707 qseecom.send_resp_flag = 0;
2708
2709 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
2710 &qsee_not_legacy, sizeof(qsee_not_legacy));
2711 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07002712 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002713 goto err;
2714 }
Mona Hossain05c73562012-10-29 17:49:01 -07002715 if (qsee_not_legacy) {
2716 uint32_t feature = 10;
2717
2718 qseecom.qsee_version = QSEEE_VERSION_00;
2719 rc = scm_call(6, 3, &feature, sizeof(feature),
2720 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
2721 if (rc) {
2722 pr_err("Failed to get QSEE version info %d\n", rc);
2723 goto err;
2724 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002725 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07002726 } else {
Mona Hossain2892b6b2012-02-17 13:53:11 -08002727 qseecom.qseos_version = QSEOS_VERSION_13;
Mona Hossain05c73562012-10-29 17:49:01 -07002728 qseecom.qsee_version = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002729 pil = NULL;
2730 pil_ref_cnt = 0;
2731 }
Mona Hossain05c73562012-10-29 17:49:01 -07002732 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002733 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002734 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07002735 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08002736 if (qseecom.ion_clnt == NULL) {
2737 pr_err("Ion client cannot be created\n");
2738 rc = -ENOMEM;
2739 goto err;
2740 }
2741
2742 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002743 if (pdev->dev.of_node) {
2744 ret = __qseecom_init_clk();
2745 if (ret)
2746 goto err;
Mona Hossain6311d572013-03-01 15:54:02 -08002747
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002748 qseecom_platform_support = (struct msm_bus_scale_pdata *)
2749 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08002750 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
2751 struct resource *resource = NULL;
2752 struct qsee_apps_region_info_ireq req;
2753 struct qseecom_command_scm_resp resp;
2754
2755 resource = platform_get_resource_byname(pdev,
2756 IORESOURCE_MEM, "secapp-region");
2757 if (resource) {
2758 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
2759 req.addr = resource->start;
2760 req.size = resource_size(resource);
2761 pr_warn("secure app region addr=0x%x size=0x%x",
2762 req.addr, req.size);
2763 } else {
2764 pr_err("Fail to get secure app region info\n");
2765 rc = -EINVAL;
2766 goto err;
2767 }
2768 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
2769 &resp, sizeof(resp));
2770 if (rc) {
2771 pr_err("Failed to send secapp region info %d\n",
2772 rc);
2773 goto err;
2774 }
2775 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002776 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07002777 qseecom_platform_support = (struct msm_bus_scale_pdata *)
2778 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002779 }
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002780
Mona Hossain17a4faf2013-03-22 16:40:56 -07002781 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002782 qseecom_platform_support);
2783
Mona Hossain17a4faf2013-03-22 16:40:56 -07002784 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002785 pr_err("Unable to register bus client\n");
2786 return 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002787err:
2788 device_destroy(driver_class, qseecom_device_no);
2789class_destroy:
2790 class_destroy(driver_class);
2791unregister_chrdev_region:
2792 unregister_chrdev_region(qseecom_device_no, 1);
2793 return rc;
2794}
2795
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002796static int __devinit qseecom_remove(struct platform_device *pdev)
2797{
Mona Hossaind44a3842012-10-15 09:41:35 -07002798 struct qseecom_registered_kclient_list *kclient = NULL;
2799 unsigned long flags = 0;
2800 int ret = 0;
2801
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002802 if (pdev->dev.platform_data != NULL)
Mona Hossain17a4faf2013-03-22 16:40:56 -07002803 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
Mona Hossaind44a3842012-10-15 09:41:35 -07002804
2805 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
2806 kclient = list_entry((&qseecom.registered_kclient_list_head)->next,
2807 struct qseecom_registered_kclient_list, list);
2808 if (list_empty(&kclient->list)) {
2809 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
2810 flags);
2811 return 0;
2812 }
2813 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
2814 list) {
2815 if (kclient)
2816 list_del(&kclient->list);
2817 break;
2818 }
2819 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
2820
2821
2822 while (kclient->handle != NULL) {
2823 ret = qseecom_unload_app(kclient->handle->dev);
2824 if (ret == 0) {
2825 kzfree(kclient->handle->dev);
2826 kzfree(kclient->handle);
2827 kzfree(kclient);
2828 }
2829 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
2830 kclient = list_entry(
2831 (&qseecom.registered_kclient_list_head)->next,
2832 struct qseecom_registered_kclient_list, list);
2833 if (list_empty(&kclient->list)) {
2834 spin_unlock_irqrestore(
2835 &qseecom.registered_kclient_list_lock, flags);
2836 return 0;
2837 }
2838 list_for_each_entry(kclient,
2839 &qseecom.registered_kclient_list_head, list) {
2840 if (kclient)
2841 list_del(&kclient->list);
2842 break;
2843 }
2844 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
2845 flags);
2846 if (!kclient) {
2847 ret = 0;
2848 break;
2849 }
2850 }
Mona Hossain05c73562012-10-29 17:49:01 -07002851 if (qseecom.qseos_version > QSEEE_VERSION_00)
2852 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08002853
Mona Hossain17a4faf2013-03-22 16:40:56 -07002854 if (qseecom.qsee_perf_client)
2855 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
2856 0);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002857 /* register client for bus scaling */
Mona Hossain6311d572013-03-01 15:54:02 -08002858 if (pdev->dev.of_node)
Mona Hossaind39e33b2012-11-05 13:36:40 -08002859 __qseecom_deinit_clk();
Mona Hossain6311d572013-03-01 15:54:02 -08002860
Mona Hossaind44a3842012-10-15 09:41:35 -07002861 return ret;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002862};
2863
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07002864static struct of_device_id qseecom_match[] = {
2865 {
2866 .compatible = "qcom,qseecom",
2867 },
2868 {}
2869};
2870
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002871static struct platform_driver qseecom_plat_driver = {
2872 .probe = qseecom_probe,
2873 .remove = qseecom_remove,
2874 .driver = {
2875 .name = "qseecom",
2876 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07002877 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002878 },
2879};
2880
2881static int __devinit qseecom_init(void)
2882{
2883 return platform_driver_register(&qseecom_plat_driver);
2884}
2885
2886static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002887{
Mona Hossain2892b6b2012-02-17 13:53:11 -08002888 device_destroy(driver_class, qseecom_device_no);
2889 class_destroy(driver_class);
2890 unregister_chrdev_region(qseecom_device_no, 1);
2891 ion_client_destroy(qseecom.ion_clnt);
2892}
2893
2894MODULE_LICENSE("GPL v2");
2895MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
2896
2897module_init(qseecom_init);
2898module_exit(qseecom_exit);