blob: 11dc436792f5c1732d333339f9a8057950db4ff5 [file] [log] [blame]
Mona Hossain803c3d92012-11-21 13:33:42 -08001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Mona Hossain11c03ac2011-10-26 12:42:10 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/debugfs.h>
14#include <linux/errno.h>
Mona Hossain803c3d92012-11-21 13:33:42 -080015#include <linux/delay.h>
Mona Hossain11c03ac2011-10-26 12:42:10 -070016#include <linux/io.h>
Mona Hossain803c3d92012-11-21 13:33:42 -080017#include <linux/msm_ion.h>
Mona Hossain11c03ac2011-10-26 12:42:10 -070018#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/platform_device.h>
21#include <linux/slab.h>
Mona Hossain803c3d92012-11-21 13:33:42 -080022#include <linux/string.h>
Mona Hossain11c03ac2011-10-26 12:42:10 -070023#include <linux/types.h>
Mona Hossain803c3d92012-11-21 13:33:42 -080024#include <linux/uaccess.h>
25#include <mach/scm.h>
26#include <mach/qseecomi.h>
Mona Hossain11c03ac2011-10-26 12:42:10 -070027
28#define DEBUG_MAX_RW_BUF 4096
29
Mona Hossain803c3d92012-11-21 13:33:42 -080030/* QSEE_LOG_BUF_SIZE = 32K */
31#define QSEE_LOG_BUF_SIZE 0x8000
32
33
34/* TZ Diagnostic Area legacy version number */
35#define TZBSP_DIAG_MAJOR_VERSION_LEGACY 2
Mona Hossain11c03ac2011-10-26 12:42:10 -070036/*
37 * Preprocessor Definitions and Constants
38 */
39#define TZBSP_CPU_COUNT 0x02
40/*
41 * Number of VMID Tables
42 */
43#define TZBSP_DIAG_NUM_OF_VMID 16
44/*
45 * VMID Description length
46 */
47#define TZBSP_DIAG_VMID_DESC_LEN 7
48/*
49 * Number of Interrupts
50 */
51#define TZBSP_DIAG_INT_NUM 32
52/*
53 * Length of descriptive name associated with Interrupt
54 */
55#define TZBSP_MAX_INT_DESC 16
56/*
57 * VMID Table
58 */
59struct tzdbg_vmid_t {
60 uint8_t vmid; /* Virtual Machine Identifier */
61 uint8_t desc[TZBSP_DIAG_VMID_DESC_LEN]; /* ASCII Text */
62};
63/*
64 * Boot Info Table
65 */
66struct tzdbg_boot_info_t {
Mona Hossainf6efb8d2012-01-24 12:30:49 -080067 uint32_t wb_entry_cnt; /* Warmboot entry CPU Counter */
68 uint32_t wb_exit_cnt; /* Warmboot exit CPU Counter */
69 uint32_t pc_entry_cnt; /* Power Collapse entry CPU Counter */
70 uint32_t pc_exit_cnt; /* Power Collapse exit CPU counter */
Mona Hossain11c03ac2011-10-26 12:42:10 -070071 uint32_t warm_jmp_addr; /* Last Warmboot Jump Address */
72 uint32_t spare; /* Reserved for future use. */
73};
74/*
75 * Reset Info Table
76 */
77struct tzdbg_reset_info_t {
78 uint32_t reset_type; /* Reset Reason */
79 uint32_t reset_cnt; /* Number of resets occured/CPU */
80};
81/*
82 * Interrupt Info Table
83 */
84struct tzdbg_int_t {
85 /*
86 * Type of Interrupt/exception
87 */
88 uint16_t int_info;
89 /*
90 * Availability of the slot
91 */
92 uint8_t avail;
93 /*
94 * Reserved for future use
95 */
96 uint8_t spare;
97 /*
98 * Interrupt # for IRQ and FIQ
99 */
100 uint32_t int_num;
101 /*
102 * ASCII text describing type of interrupt e.g:
103 * Secure Timer, EBI XPU. This string is always null terminated,
104 * supporting at most TZBSP_MAX_INT_DESC characters.
105 * Any additional characters are truncated.
106 */
107 uint8_t int_desc[TZBSP_MAX_INT_DESC];
108 uint64_t int_count[TZBSP_CPU_COUNT]; /* # of times seen per CPU */
109};
Mona Hossain803c3d92012-11-21 13:33:42 -0800110
111/*
112 * Log ring buffer position
113 */
114struct tzdbg_log_pos_t {
115 uint16_t wrap;
116 uint16_t offset;
117};
118
119 /*
120 * Log ring buffer
121 */
122struct tzdbg_log_t {
123 struct tzdbg_log_pos_t log_pos;
124 /* open ended array to the end of the 4K IMEM buffer */
125 uint8_t log_buf[];
126};
127
Mona Hossain11c03ac2011-10-26 12:42:10 -0700128/*
129 * Diagnostic Table
130 */
131struct tzdbg_t {
132 uint32_t magic_num;
133 uint32_t version;
134 /*
135 * Number of CPU's
136 */
137 uint32_t cpu_count;
138 /*
139 * Offset of VMID Table
140 */
141 uint32_t vmid_info_off;
142 /*
143 * Offset of Boot Table
144 */
145 uint32_t boot_info_off;
146 /*
147 * Offset of Reset info Table
148 */
149 uint32_t reset_info_off;
150 /*
151 * Offset of Interrupt info Table
152 */
153 uint32_t int_info_off;
154 /*
155 * Ring Buffer Offset
156 */
157 uint32_t ring_off;
158 /*
159 * Ring Buffer Length
160 */
161 uint32_t ring_len;
162 /*
163 * VMID to EE Mapping
164 */
165 struct tzdbg_vmid_t vmid_info[TZBSP_DIAG_NUM_OF_VMID];
166 /*
167 * Boot Info
168 */
169 struct tzdbg_boot_info_t boot_info[TZBSP_CPU_COUNT];
170 /*
171 * Reset Info
172 */
173 struct tzdbg_reset_info_t reset_info[TZBSP_CPU_COUNT];
174 uint32_t num_interrupts;
175 struct tzdbg_int_t int_info[TZBSP_DIAG_INT_NUM];
176 /*
177 * We need at least 2K for the ring buffer
178 */
Mona Hossain803c3d92012-11-21 13:33:42 -0800179 struct tzdbg_log_t ring_buffer; /* TZ Ring Buffer */
Mona Hossain11c03ac2011-10-26 12:42:10 -0700180};
181
182/*
183 * Enumeration order for VMID's
184 */
185enum tzdbg_stats_type {
186 TZDBG_BOOT = 0,
187 TZDBG_RESET,
188 TZDBG_INTERRUPT,
189 TZDBG_VMID,
190 TZDBG_GENERAL,
191 TZDBG_LOG,
Mona Hossain803c3d92012-11-21 13:33:42 -0800192 TZDBG_QSEE_LOG,
193 TZDBG_STATS_MAX
Mona Hossain11c03ac2011-10-26 12:42:10 -0700194};
195
196struct tzdbg_stat {
197 char *name;
198 char *data;
199};
200
201struct tzdbg {
202 void __iomem *virt_iobase;
203 struct tzdbg_t *diag_buf;
204 char *disp_buf;
205 int debug_tz[TZDBG_STATS_MAX];
206 struct tzdbg_stat stat[TZDBG_STATS_MAX];
207};
208
209static struct tzdbg tzdbg = {
210
211 .stat[TZDBG_BOOT].name = "boot",
212 .stat[TZDBG_RESET].name = "reset",
213 .stat[TZDBG_INTERRUPT].name = "interrupt",
214 .stat[TZDBG_VMID].name = "vmid",
215 .stat[TZDBG_GENERAL].name = "general",
216 .stat[TZDBG_LOG].name = "log",
Mona Hossain803c3d92012-11-21 13:33:42 -0800217 .stat[TZDBG_QSEE_LOG].name = "qsee_log",
Mona Hossain11c03ac2011-10-26 12:42:10 -0700218};
219
Mona Hossain803c3d92012-11-21 13:33:42 -0800220static struct tzdbg_log_t *g_qsee_log;
Mona Hossain11c03ac2011-10-26 12:42:10 -0700221
222/*
223 * Debugfs data structure and functions
224 */
225
226static int _disp_tz_general_stats(void)
227{
228 int len = 0;
229
230 len += snprintf(tzdbg.disp_buf + len, DEBUG_MAX_RW_BUF - 1,
231 " Version : 0x%x\n"
232 " Magic Number : 0x%x\n"
233 " Number of CPU : %d\n",
234 tzdbg.diag_buf->version,
235 tzdbg.diag_buf->magic_num,
236 tzdbg.diag_buf->cpu_count);
237 tzdbg.stat[TZDBG_GENERAL].data = tzdbg.disp_buf;
238 return len;
239}
240
241static int _disp_tz_vmid_stats(void)
242{
243 int i, num_vmid;
244 int len = 0;
245 struct tzdbg_vmid_t *ptr;
246
247 ptr = (struct tzdbg_vmid_t *)((unsigned char *)tzdbg.diag_buf +
248 tzdbg.diag_buf->vmid_info_off);
249 num_vmid = ((tzdbg.diag_buf->boot_info_off -
250 tzdbg.diag_buf->vmid_info_off)/
251 (sizeof(struct tzdbg_vmid_t)));
252
253 for (i = 0; i < num_vmid; i++) {
254 if (ptr->vmid < 0xFF) {
255 len += snprintf(tzdbg.disp_buf + len,
256 (DEBUG_MAX_RW_BUF - 1) - len,
257 " 0x%x %s\n",
258 (uint32_t)ptr->vmid, (uint8_t *)ptr->desc);
259 }
260 if (len > (DEBUG_MAX_RW_BUF - 1)) {
261 pr_warn("%s: Cannot fit all info into the buffer\n",
262 __func__);
263 break;
264 }
265 ptr++;
266 }
267
268 tzdbg.stat[TZDBG_VMID].data = tzdbg.disp_buf;
269 return len;
270}
271
272static int _disp_tz_boot_stats(void)
273{
274 int i;
275 int len = 0;
276 struct tzdbg_boot_info_t *ptr;
277
278 ptr = (struct tzdbg_boot_info_t *)((unsigned char *)tzdbg.diag_buf +
279 tzdbg.diag_buf->boot_info_off);
280
281 for (i = 0; i < tzdbg.diag_buf->cpu_count; i++) {
282 len += snprintf(tzdbg.disp_buf + len,
283 (DEBUG_MAX_RW_BUF - 1) - len,
284 " CPU #: %d\n"
285 " Warmboot jump address : 0x%x\n"
286 " Warmboot entry CPU counter: 0x%x\n"
Mona Hossainf6efb8d2012-01-24 12:30:49 -0800287 " Warmboot exit CPU counter : 0x%x\n"
288 " Power Collapse entry CPU counter: 0x%x\n"
289 " Power Collapse exit CPU counter : 0x%x\n",
290 i, ptr->warm_jmp_addr, ptr->wb_entry_cnt,
291 ptr->wb_exit_cnt, ptr->pc_entry_cnt,
292 ptr->pc_exit_cnt);
Mona Hossain11c03ac2011-10-26 12:42:10 -0700293
294 if (len > (DEBUG_MAX_RW_BUF - 1)) {
295 pr_warn("%s: Cannot fit all info into the buffer\n",
296 __func__);
297 break;
298 }
299 ptr++;
300 }
301 tzdbg.stat[TZDBG_BOOT].data = tzdbg.disp_buf;
302 return len;
303}
304
305static int _disp_tz_reset_stats(void)
306{
307 int i;
308 int len = 0;
309 struct tzdbg_reset_info_t *ptr;
310
311 ptr = (struct tzdbg_reset_info_t *)((unsigned char *)tzdbg.diag_buf +
312 tzdbg.diag_buf->reset_info_off);
313
314 for (i = 0; i < tzdbg.diag_buf->cpu_count; i++) {
315 len += snprintf(tzdbg.disp_buf + len,
316 (DEBUG_MAX_RW_BUF - 1) - len,
317 " CPU #: %d\n"
318 " Reset Type (reason) : 0x%x\n"
319 " Reset counter : 0x%x\n",
320 i, ptr->reset_type, ptr->reset_cnt);
321
322 if (len > (DEBUG_MAX_RW_BUF - 1)) {
323 pr_warn("%s: Cannot fit all info into the buffer\n",
324 __func__);
325 break;
326 }
327
328 ptr++;
329 }
330 tzdbg.stat[TZDBG_RESET].data = tzdbg.disp_buf;
331 return len;
332}
333
334static int _disp_tz_interrupt_stats(void)
335{
336 int i, j, int_info_size;
337 int len = 0;
338 int *num_int;
339 unsigned char *ptr;
340 struct tzdbg_int_t *tzdbg_ptr;
341
342 num_int = (uint32_t *)((unsigned char *)tzdbg.diag_buf +
343 (tzdbg.diag_buf->int_info_off - sizeof(uint32_t)));
344 ptr = ((unsigned char *)tzdbg.diag_buf +
345 tzdbg.diag_buf->int_info_off);
346 int_info_size = ((tzdbg.diag_buf->ring_off -
347 tzdbg.diag_buf->int_info_off)/(*num_int));
348
349 for (i = 0; i < (*num_int); i++) {
350 tzdbg_ptr = (struct tzdbg_int_t *)ptr;
351 len += snprintf(tzdbg.disp_buf + len,
352 (DEBUG_MAX_RW_BUF - 1) - len,
353 " Interrupt Number : 0x%x\n"
354 " Type of Interrupt : 0x%x\n"
355 " Description of interrupt : %s\n",
356 tzdbg_ptr->int_num,
357 (uint32_t)tzdbg_ptr->int_info,
358 (uint8_t *)tzdbg_ptr->int_desc);
359 for (j = 0; j < tzdbg.diag_buf->cpu_count; j++) {
360 len += snprintf(tzdbg.disp_buf + len,
361 (DEBUG_MAX_RW_BUF - 1) - len,
362 " int_count on CPU # %d : %u\n",
363 (uint32_t)j,
364 (uint32_t)tzdbg_ptr->int_count[j]);
365 }
366 len += snprintf(tzdbg.disp_buf + len, DEBUG_MAX_RW_BUF - 1,
367 "\n");
368
369 if (len > (DEBUG_MAX_RW_BUF - 1)) {
370 pr_warn("%s: Cannot fit all info into the buffer\n",
371 __func__);
372 break;
373 }
374
375 ptr += int_info_size;
376 }
377 tzdbg.stat[TZDBG_INTERRUPT].data = tzdbg.disp_buf;
378 return len;
379}
380
Mona Hossain803c3d92012-11-21 13:33:42 -0800381static int _disp_tz_log_stats_legacy(void)
Mona Hossain11c03ac2011-10-26 12:42:10 -0700382{
383 int len = 0;
384 unsigned char *ptr;
385
386 ptr = (unsigned char *)tzdbg.diag_buf +
387 tzdbg.diag_buf->ring_off;
388 len += snprintf(tzdbg.disp_buf, (DEBUG_MAX_RW_BUF - 1) - len,
389 "%s\n", ptr);
390
391 tzdbg.stat[TZDBG_LOG].data = tzdbg.disp_buf;
392 return len;
393}
394
Mona Hossain803c3d92012-11-21 13:33:42 -0800395static int _disp_log_stats(struct tzdbg_log_t *log,
396 struct tzdbg_log_pos_t *log_start, uint32_t log_len,
397 size_t count, uint32_t buf_idx)
398{
399 uint32_t wrap_start;
400 uint32_t wrap_end;
401 uint32_t wrap_cnt;
402 int max_len;
403 int len = 0;
404 int i = 0;
405
406 wrap_start = log_start->wrap;
407 wrap_end = log->log_pos.wrap;
408
409 /* Calculate difference in # of buffer wrap-arounds */
410 if (wrap_end >= wrap_start) {
411 wrap_cnt = wrap_end - wrap_start;
412 } else {
413 /* wrap counter has wrapped around, invalidate start position */
414 wrap_cnt = 2;
415 }
416
417 if (wrap_cnt > 1) {
418 /* end position has wrapped around more than once, */
419 /* current start no longer valid */
420 log_start->wrap = log->log_pos.wrap - 1;
421 log_start->offset = (log->log_pos.offset + 1) % log_len;
422 } else if ((wrap_cnt == 1) &&
423 (log->log_pos.offset > log_start->offset)) {
424 /* end position has overwritten start */
425 log_start->offset = (log->log_pos.offset + 1) % log_len;
426 }
427
428 while (log_start->offset == log->log_pos.offset) {
429 /*
430 * No data in ring buffer,
431 * so we'll hang around until something happens
432 */
433 unsigned long t = msleep_interruptible(50);
434 if (t != 0) {
435 /* Some event woke us up, so let's quit */
436 return 0;
437 }
438
439 if (buf_idx == TZDBG_LOG)
440 memcpy_fromio((void *)tzdbg.diag_buf, tzdbg.virt_iobase,
441 DEBUG_MAX_RW_BUF);
442
443 }
444
445 max_len = (count > DEBUG_MAX_RW_BUF) ? DEBUG_MAX_RW_BUF : count;
446
447 /*
448 * Read from ring buff while there is data and space in return buff
449 */
450 while ((log_start->offset != log->log_pos.offset) && (len < max_len)) {
451 tzdbg.disp_buf[i++] = log->log_buf[log_start->offset];
452 log_start->offset = (log_start->offset + 1) % log_len;
453 if (0 == log_start->offset)
454 ++log_start->wrap;
455 ++len;
456 }
457
458 /*
459 * return buffer to caller
460 */
461 tzdbg.stat[buf_idx].data = tzdbg.disp_buf;
462 return len;
463}
464
465static int _disp_tz_log_stats(size_t count)
466{
467 static struct tzdbg_log_pos_t log_start = {0};
468 struct tzdbg_log_t *log_ptr;
469 log_ptr = (struct tzdbg_log_t *)((unsigned char *)tzdbg.diag_buf +
470 tzdbg.diag_buf->ring_off -
471 offsetof(struct tzdbg_log_t, log_buf));
472
473 return _disp_log_stats(log_ptr, &log_start,
474 tzdbg.diag_buf->ring_len, count, TZDBG_LOG);
475}
476
477static int _disp_qsee_log_stats(size_t count)
478{
479 static struct tzdbg_log_pos_t log_start = {0};
480
481 return _disp_log_stats(g_qsee_log, &log_start,
482 QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_t),
483 count, TZDBG_QSEE_LOG);
484}
485
Mona Hossain11c03ac2011-10-26 12:42:10 -0700486static ssize_t tzdbgfs_read(struct file *file, char __user *buf,
487 size_t count, loff_t *offp)
488{
489 int len = 0;
490 int *tz_id = file->private_data;
491
492 memcpy_fromio((void *)tzdbg.diag_buf, tzdbg.virt_iobase,
493 DEBUG_MAX_RW_BUF);
494 switch (*tz_id) {
495 case TZDBG_BOOT:
496 len = _disp_tz_boot_stats();
497 break;
498 case TZDBG_RESET:
499 len = _disp_tz_reset_stats();
500 break;
501 case TZDBG_INTERRUPT:
502 len = _disp_tz_interrupt_stats();
503 break;
504 case TZDBG_GENERAL:
505 len = _disp_tz_general_stats();
506 break;
507 case TZDBG_VMID:
508 len = _disp_tz_vmid_stats();
509 break;
510 case TZDBG_LOG:
Mona Hossain803c3d92012-11-21 13:33:42 -0800511 if (TZBSP_DIAG_MAJOR_VERSION_LEGACY <
512 (tzdbg.diag_buf->version >> 16)) {
513 len = _disp_tz_log_stats(count);
514 *offp = 0;
515 } else {
516 len = _disp_tz_log_stats_legacy();
517 }
518 break;
519 case TZDBG_QSEE_LOG:
520 len = _disp_qsee_log_stats(count);
521 *offp = 0;
Mona Hossain11c03ac2011-10-26 12:42:10 -0700522 break;
523 default:
524 break;
525 }
526
527 if (len > count)
528 len = count;
529
530 return simple_read_from_buffer(buf, len, offp,
531 tzdbg.stat[(*tz_id)].data, len);
532}
533
534static int tzdbgfs_open(struct inode *inode, struct file *pfile)
535{
536 pfile->private_data = inode->i_private;
537 return 0;
538}
539
540const struct file_operations tzdbg_fops = {
541 .owner = THIS_MODULE,
542 .read = tzdbgfs_read,
543 .open = tzdbgfs_open,
544};
545
Mona Hossain803c3d92012-11-21 13:33:42 -0800546static struct ion_client *g_ion_clnt;
547static struct ion_handle *g_ihandle;
548
549/*
550 * Allocates log buffer from ION, registers the buffer at TZ
551 */
552static void tzdbg_register_qsee_log_buf(void)
553{
554 /* register log buffer scm request */
555 struct qseecom_reg_log_buf_ireq req;
556
557 /* scm response */
558 struct qseecom_command_scm_resp resp;
559 ion_phys_addr_t pa = 0;
560 uint32_t len;
561 int ret = 0;
562
563 /* Create ION msm client */
564 g_ion_clnt = msm_ion_client_create(ION_HEAP_CARVEOUT_MASK, "qsee_log");
565 if (g_ion_clnt == NULL) {
566 pr_err("%s: Ion client cannot be created\n", __func__);
567 return;
568 }
569
570 g_ihandle = ion_alloc(g_ion_clnt, QSEE_LOG_BUF_SIZE,
571 4096, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
572 if (IS_ERR_OR_NULL(g_ihandle)) {
573 pr_err("%s: Ion client could not retrieve the handle\n",
574 __func__);
575 goto err1;
576 }
577
578 ret = ion_phys(g_ion_clnt, g_ihandle, &pa, &len);
579 if (ret) {
580 pr_err("%s: Ion conversion to physical address failed\n",
581 __func__);
582 goto err2;
583 }
584
585 req.qsee_cmd_id = QSEOS_REGISTER_LOG_BUF_COMMAND;
586 req.phy_addr = pa;
587 req.len = len;
588
589 /* SCM_CALL to register the log buffer */
590 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
591 &resp, sizeof(resp));
592 if (ret) {
593 pr_err("%s: scm_call to register log buffer failed\n",
594 __func__);
595 goto err2;
596 }
597
598 if (resp.result != QSEOS_RESULT_SUCCESS) {
599 pr_err(
600 "%s: scm_call to register log buf failed, resp result =%d\n",
601 __func__, resp.result);
602 goto err2;
603 }
604
605 g_qsee_log =
606 (struct tzdbg_log_t *)ion_map_kernel(g_ion_clnt, g_ihandle);
607 g_qsee_log->log_pos.wrap = g_qsee_log->log_pos.offset = 0;
608 return;
609
610err2:
611 ion_free(g_ion_clnt, g_ihandle);
612 g_ihandle = NULL;
613err1:
614 ion_client_destroy(g_ion_clnt);
615 g_ion_clnt = NULL;
616}
617
Mona Hossain11c03ac2011-10-26 12:42:10 -0700618static int tzdbgfs_init(struct platform_device *pdev)
619{
620 int rc = 0;
621 int i;
622 struct dentry *dent_dir;
623 struct dentry *dent;
624
625 dent_dir = debugfs_create_dir("tzdbg", NULL);
626 if (dent_dir == NULL) {
627 dev_err(&pdev->dev, "tzdbg debugfs_create_dir failed\n");
628 return -ENOMEM;
629 }
630
631 for (i = 0; i < TZDBG_STATS_MAX; i++) {
632 tzdbg.debug_tz[i] = i;
633 dent = debugfs_create_file(tzdbg.stat[i].name,
634 S_IRUGO, dent_dir,
635 &tzdbg.debug_tz[i], &tzdbg_fops);
636 if (dent == NULL) {
637 dev_err(&pdev->dev, "TZ debugfs_create_file failed\n");
638 rc = -ENOMEM;
639 goto err;
640 }
641 }
642 tzdbg.disp_buf = kzalloc(DEBUG_MAX_RW_BUF, GFP_KERNEL);
643 if (tzdbg.disp_buf == NULL) {
644 pr_err("%s: Can't Allocate memory for tzdbg.disp_buf\n",
645 __func__);
646
647 goto err;
648 }
649 platform_set_drvdata(pdev, dent_dir);
650 return 0;
651err:
652 debugfs_remove_recursive(dent_dir);
653
654 return rc;
655}
656
657static void tzdbgfs_exit(struct platform_device *pdev)
658{
659 struct dentry *dent_dir;
660
661 kzfree(tzdbg.disp_buf);
662 dent_dir = platform_get_drvdata(pdev);
663 debugfs_remove_recursive(dent_dir);
Mona Hossain803c3d92012-11-21 13:33:42 -0800664 if (g_ion_clnt != NULL) {
665 if (!IS_ERR_OR_NULL(g_ihandle)) {
666 ion_unmap_kernel(g_ion_clnt, g_ihandle);
667 ion_free(g_ion_clnt, g_ihandle);
668 }
669 ion_client_destroy(g_ion_clnt);
670}
Mona Hossain11c03ac2011-10-26 12:42:10 -0700671}
672
673/*
674 * Driver functions
675 */
676static int __devinit tz_log_probe(struct platform_device *pdev)
677{
678 struct resource *resource;
679 void __iomem *virt_iobase;
680 uint32_t tzdiag_phy_iobase;
681 uint32_t *ptr = NULL;
682
683 /*
684 * Get address that stores the physical location of 4KB
685 * diagnostic data
686 */
687 resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
688 if (!resource) {
689 dev_err(&pdev->dev,
690 "%s: ERROR Missing MEM resource\n", __func__);
691 return -ENXIO;
692 };
693 /*
694 * Map address that stores the physical location of 4KB
695 * diagnostic data
696 */
697 virt_iobase = devm_ioremap_nocache(&pdev->dev, resource->start,
698 resource->end - resource->start + 1);
699 if (!virt_iobase) {
700 dev_err(&pdev->dev,
701 "%s: ERROR could not ioremap: start=%p, len=%u\n",
702 __func__, (void *) resource->start,
703 (resource->end - resource->start + 1));
704 return -ENXIO;
705 }
706 /*
707 * Retrieve the address of 4KB diagnostic data
708 */
709 tzdiag_phy_iobase = readl_relaxed(virt_iobase);
710
Hariprasad Dhalinarasimhaa7737d42012-10-01 19:56:27 -0700711 if (!pdev->dev.of_node) {
Mona Hossain11c03ac2011-10-26 12:42:10 -0700712
Hariprasad Dhalinarasimhaa7737d42012-10-01 19:56:27 -0700713 /*
714 * Map the 4KB diagnostic information area
715 */
716 tzdbg.virt_iobase = devm_ioremap_nocache(&pdev->dev,
717 tzdiag_phy_iobase, DEBUG_MAX_RW_BUF);
718
719 if (!tzdbg.virt_iobase) {
720 dev_err(&pdev->dev,
721 "%s: ERROR could not ioremap: start=%p, len=%u\n",
722 __func__, (void *) tzdiag_phy_iobase,
723 DEBUG_MAX_RW_BUF);
724 return -ENXIO;
725 }
726 } else {
727 tzdbg.virt_iobase = virt_iobase;
Mona Hossain11c03ac2011-10-26 12:42:10 -0700728 }
729
730 ptr = kzalloc(DEBUG_MAX_RW_BUF, GFP_KERNEL);
731 if (ptr == NULL) {
732 pr_err("%s: Can't Allocate memory: ptr\n",
733 __func__);
734 return -ENXIO;
735 }
736
737 tzdbg.diag_buf = (struct tzdbg_t *)ptr;
738
739 if (tzdbgfs_init(pdev))
740 goto err;
741
Mona Hossain803c3d92012-11-21 13:33:42 -0800742 tzdbg_register_qsee_log_buf();
Mona Hossain11c03ac2011-10-26 12:42:10 -0700743 return 0;
744err:
745 kfree(tzdbg.diag_buf);
746 return -ENXIO;
747}
748
749
750static int __devexit tz_log_remove(struct platform_device *pdev)
751{
752 kzfree(tzdbg.diag_buf);
753 tzdbgfs_exit(pdev);
754
755 return 0;
756}
757
Hariprasad Dhalinarasimha71b536f2012-06-28 17:39:35 -0700758static struct of_device_id tzlog_match[] = {
759 { .compatible = "qcom,tz-log",
760 },
761 {}
762};
763
Mona Hossain11c03ac2011-10-26 12:42:10 -0700764static struct platform_driver tz_log_driver = {
765 .probe = tz_log_probe,
766 .remove = __devexit_p(tz_log_remove),
767 .driver = {
768 .name = "tz_log",
769 .owner = THIS_MODULE,
Hariprasad Dhalinarasimha71b536f2012-06-28 17:39:35 -0700770 .of_match_table = tzlog_match,
Mona Hossain11c03ac2011-10-26 12:42:10 -0700771 },
772};
773
774static int __init tz_log_init(void)
775{
776 return platform_driver_register(&tz_log_driver);
777}
778
779static void __exit tz_log_exit(void)
780{
781 platform_driver_unregister(&tz_log_driver);
782}
783
784module_init(tz_log_init);
785module_exit(tz_log_exit);
786
787MODULE_LICENSE("GPL v2");
788MODULE_DESCRIPTION("TZ Log driver");
Mona Hossainf6efb8d2012-01-24 12:30:49 -0800789MODULE_VERSION("1.1");
Mona Hossain11c03ac2011-10-26 12:42:10 -0700790MODULE_ALIAS("platform:tz_log");