]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/remoteproc/qcom_tz_pil.c
Move to new qcom_smem_get() api
[karo-tx-linux.git] / drivers / remoteproc / qcom_tz_pil.c
1 /*
2  * Qualcomm Peripheral Image Loader
3  *
4  * Copyright (C) 2014 Sony Mobile Communications AB
5  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * 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 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/platform_device.h>
20 #include <linux/dma-mapping.h>
21 #include <linux/firmware.h>
22 #include <linux/remoteproc.h>
23 #include <linux/interrupt.h>
24 #include <linux/memblock.h>
25 #include <linux/gpio/consumer.h>
26 #include <linux/of.h>
27 #include <linux/elf.h>
28 #include <linux/clk.h>
29 #include <linux/slab.h>
30 #include <linux/regulator/consumer.h>
31 #include <linux/qcom_scm.h>
32 #include <linux/soc/qcom/smem.h>
33 #include <linux/of.h>
34 #include <linux/of_address.h>
35 #include <linux/delay.h>
36 #include <linux/soc/qcom/smd.h>
37
38 #include "remoteproc_internal.h"
39
40 #define PAS_INIT_IMAGE_CMD      1
41 #define PAS_MEM_SETUP_CMD       2
42 #define PAS_AUTH_AND_RESET_CMD  5
43 #define PAS_SHUTDOWN_CMD        6
44 #define PAS_IS_SUPPORTED_CMD    7
45
46 struct qproc {
47         struct device *dev;
48         struct rproc *rproc;
49
50         int pas_id;
51
52         int wdog_irq;
53         int fatal_irq;
54         int ready_irq;
55         int handover_irq;
56         int stop_ack_irq;
57
58         struct gpio_desc *stop_gpio;
59
60         const char *name;
61         struct regulator *pll;
62
63         unsigned proxy_clk_count;
64         bool    no_scm_clks;
65         struct clk *scm_core_clk;
66         struct clk *scm_iface_clk;
67         struct clk *scm_bus_clk;
68         struct clk *scm_src_clk;
69
70         struct clk **proxy_clks;
71
72         struct completion start_done;
73         struct completion stop_done;
74
75         unsigned crash_reason;
76         struct device_node *smd_edge_node;
77
78         phys_addr_t reloc_phys;
79         size_t reloc_size;
80 };
81
82 static int qproc_scm_clk_enable(struct qproc *qproc)
83 {
84         int ret;
85
86         if (qproc->no_scm_clks)
87                 return 0;
88
89         ret = clk_prepare_enable(qproc->scm_core_clk);
90         if (ret)
91                 goto bail;
92         ret = clk_prepare_enable(qproc->scm_iface_clk);
93         if (ret)
94                 goto disable_core;
95         ret = clk_prepare_enable(qproc->scm_bus_clk);
96         if (ret)
97                 goto disable_iface;
98
99         ret = clk_prepare_enable(qproc->scm_src_clk);
100         if (ret)
101                 goto disable_bus;
102
103         return 0;
104
105 disable_bus:
106         clk_disable_unprepare(qproc->scm_bus_clk);
107 disable_iface:
108         clk_disable_unprepare(qproc->scm_iface_clk);
109 disable_core:
110         clk_disable_unprepare(qproc->scm_core_clk);
111 bail:
112         return ret;
113 }
114
115 static void qproc_scm_clk_disable(struct qproc *qproc)
116 {
117         if (qproc->no_scm_clks)
118                 return;
119
120         clk_disable_unprepare(qproc->scm_core_clk);
121         clk_disable_unprepare(qproc->scm_iface_clk);
122         clk_disable_unprepare(qproc->scm_bus_clk);
123         clk_disable_unprepare(qproc->scm_src_clk);
124 }
125
126 /**
127  * struct pil_mdt - Representation of <name>.mdt file in memory
128  * @hdr: ELF32 header
129  * @phdr: ELF32 program headers
130  */
131 struct mdt_hdr {
132         struct elf32_hdr hdr;
133         struct elf32_phdr phdr[];
134 };
135
136 #define segment_is_hash(flag) (((flag) & (0x7 << 24)) == (0x2 << 24))
137
138 static int segment_is_loadable(const struct elf32_phdr *p)
139 {
140         return (p->p_type == PT_LOAD) &&
141                !segment_is_hash(p->p_flags) &&
142                p->p_memsz;
143 }
144
145 static bool segment_is_relocatable(const struct elf32_phdr *p)
146 {
147         return !!(p->p_flags & BIT(27));
148 }
149
150 /**
151  * rproc_mdt_sanity_check() - sanity check mdt firmware header
152  * @rproc: the remote processor handle
153  * @fw: the mdt header firmware image
154  */
155 static int qproc_sanity_check(struct rproc *rproc,
156                                   const struct firmware *fw)
157 {
158         struct elf32_hdr *ehdr;
159         struct mdt_hdr *mdt;
160
161         if (!fw) {
162                 dev_err(&rproc->dev, "failed to load %s\n", rproc->name);
163                 return -EINVAL;
164         }
165
166         if (fw->size < sizeof(struct elf32_hdr)) {
167                 dev_err(&rproc->dev, "image is too small\n");
168                 return -EINVAL;
169         }
170
171         mdt = (struct mdt_hdr *)fw->data;
172         ehdr = &mdt->hdr;
173
174         if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
175                 dev_err(&rproc->dev, "image is corrupted (bad magic)\n");
176                 return -EINVAL;
177         }
178
179         if (ehdr->e_phnum == 0) {
180                 dev_err(&rproc->dev, "no loadable segments\n");
181                 return -EINVAL;
182         }
183
184         if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
185             sizeof(struct elf32_hdr) > fw->size) {
186                 dev_err(&rproc->dev, "firmware size is too small\n");
187                 return -EINVAL;
188         }
189
190         return 0;
191 }
192
193 static struct resource_table * qproc_find_rsc_table(struct rproc *rproc,
194                                                     const struct firmware *fw,
195                                                     int *tablesz)
196 {
197         static struct resource_table table = { .ver = 1, };
198
199         *tablesz = sizeof(table);
200         return &table;
201 }
202
203 static int qproc_load_segment(struct rproc *rproc, const char *fw_name,
204                                 const struct elf32_phdr *phdr, phys_addr_t paddr)
205 {
206         const struct firmware *fw;
207         void *ptr;
208         int ret = 0;
209
210         ptr = ioremap_nocache(paddr, phdr->p_memsz);
211         if (!ptr) {
212                 dev_err(&rproc->dev, "failed to ioremap segment area (%pa+0x%x)\n", &paddr, phdr->p_memsz);
213                 return -EBUSY;
214         }
215
216         if (phdr->p_filesz) {
217                 ret = request_firmware(&fw, fw_name, &rproc->dev);
218                 if (ret) {
219                         dev_err(&rproc->dev, "failed to load %s\n", fw_name);
220                         goto out;
221                 }
222
223                 memcpy_toio(ptr, fw->data, fw->size);
224
225                 release_firmware(fw);
226         }
227
228         if (phdr->p_memsz > phdr->p_filesz)
229                 memset_io(ptr + phdr->p_filesz, 0,
230                           phdr->p_memsz - phdr->p_filesz);
231
232 out:
233         iounmap(ptr);
234         return ret;
235 }
236
237 static int qproc_load(struct rproc *rproc, const struct firmware *fw)
238 {
239         const struct elf32_phdr *phdr;
240         const struct elf32_hdr *ehdr;
241         const struct mdt_hdr *mdt;
242         phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
243         phys_addr_t max_addr = 0;
244         phys_addr_t diff_addr;
245         struct qproc *qproc = rproc->priv;
246         char *fw_name;
247         int ret;
248         int i;
249         size_t align = 0;
250         bool relocatable = false;
251         phys_addr_t paddr;
252
253         ret = qproc_scm_clk_enable(qproc);
254         if (ret)
255                 return ret;
256
257         mdt = (struct mdt_hdr *)fw->data;
258         ehdr = &mdt->hdr;
259
260         for (i = 0; i < ehdr->e_phnum; i++) {
261                 phdr = &mdt->phdr[i];
262
263                 if (!segment_is_loadable(phdr))
264                         continue;
265
266                 if (phdr->p_paddr < min_addr) {
267                         min_addr = phdr->p_paddr;
268
269                         if (segment_is_relocatable(phdr)) {
270                                 align = phdr->p_align;
271                                 relocatable = true;
272                         }
273                 }
274
275                 if (phdr->p_paddr + phdr->p_memsz > max_addr)
276                         max_addr = round_up(phdr->p_paddr + phdr->p_memsz, SZ_4K);
277         }
278
279         ret = qcom_scm_pas_init_image(qproc->dev,
280                                 qproc->pas_id, fw->data, fw->size);
281         if (ret) {
282                 dev_err(qproc->dev, "Invalid firmware metadata\n");
283                 return -EINVAL;
284         }
285
286         diff_addr = max_addr - min_addr;
287         dev_dbg(qproc->dev, "pas_mem_setup %pa, %pa\n", &min_addr, &diff_addr);
288
289         ret = qcom_scm_pas_mem_setup(qproc->pas_id,
290                 relocatable ? qproc->reloc_phys : min_addr, max_addr - min_addr);
291         if (ret) {
292                 dev_err(qproc->dev, "unable to setup memory for image\n");
293                 return -EINVAL;
294         }
295
296         fw_name = kzalloc(strlen(qproc->name) + 5, GFP_KERNEL);
297         if (!fw_name)
298                 return -ENOMEM;
299
300         for (i = 0; i < ehdr->e_phnum; i++) {
301                 phdr = &mdt->phdr[i];
302
303                 if (!segment_is_loadable(phdr))
304                         continue;
305
306                 paddr = relocatable ?
307                                 (phdr->p_paddr - min_addr + qproc->reloc_phys) :
308                                 phdr->p_paddr;
309                 sprintf(fw_name, "%s.b%02d", qproc->name, i);
310                 ret = qproc_load_segment(rproc, fw_name, phdr, paddr);
311                 if (ret)
312                         break;
313         }
314
315         kfree(fw_name);
316
317         qproc_scm_clk_disable(qproc);
318
319         return 0;
320 }
321
322 const struct rproc_fw_ops qproc_fw_ops = {
323         .find_rsc_table = qproc_find_rsc_table,
324         .load = qproc_load,
325         .sanity_check = qproc_sanity_check,
326 };
327
328 static int qproc_start(struct rproc *rproc)
329 {
330         struct qproc *qproc = (struct qproc *)rproc->priv;
331         int ret;
332
333         ret = regulator_enable(qproc->pll);
334         if (ret) {
335                 dev_err(qproc->dev, "failed to enable pll supply\n");
336                 return ret;
337         }
338
339         ret = qproc_scm_clk_enable(qproc);
340         if (ret)
341                 goto disable_regulator;
342
343         ret = qcom_scm_pas_auth_and_reset(qproc->pas_id);
344         if (ret) {
345                 dev_err(qproc->dev,
346                                 "failed to authenticate image and release reset\n");
347                 goto unroll_clocks;
348         }
349
350         /* if ready irq not provided skip waiting */
351         if (qproc->ready_irq < 0)
352                 goto done;
353
354         ret = wait_for_completion_timeout(&qproc->start_done, msecs_to_jiffies(10000));
355         if (ret == 0) {
356                 dev_err(qproc->dev, "start timed out\n");
357
358                 qcom_scm_pas_shutdown(qproc->pas_id);
359                 goto unroll_clocks;
360         }
361
362 done:
363         dev_info(qproc->dev, "start successful\n");
364
365         return 0;
366
367 unroll_clocks:
368         qproc_scm_clk_disable(qproc);
369
370 disable_regulator:
371         regulator_disable(qproc->pll);
372
373         return ret;
374 }
375
376 static int qproc_stop(struct rproc *rproc)
377 {
378         return 0;
379 }
380
381 static const struct rproc_ops qproc_ops = {
382         .start = qproc_start,
383         .stop = qproc_stop,
384 };
385
386 static irqreturn_t qproc_wdog_interrupt(int irq, void *dev)
387 {
388         struct qproc *qproc = dev;
389
390         rproc_report_crash(qproc->rproc, RPROC_WATCHDOG);
391         return IRQ_HANDLED;
392 }
393
394 static irqreturn_t qproc_fatal_interrupt(int irq, void *dev)
395 {
396         struct qproc *qproc = dev;
397         size_t len;
398         char *msg;
399         int ret;
400
401         msg = qcom_smem_get(-1, qproc->crash_reason, &len);
402         if (IS_ERR(msg) && len > 0 && msg[0])
403                 dev_err(qproc->dev, "fatal error received: %s\n", msg);
404
405         rproc_report_crash(qproc->rproc, RPROC_FATAL_ERROR);
406
407         if (!ret)
408                 msg[0] = '\0';
409
410         return IRQ_HANDLED;
411 }
412
413 static irqreturn_t qproc_ready_interrupt(int irq, void *dev)
414 {
415         struct qproc *qproc = dev;
416
417         complete(&qproc->start_done);
418
419         return IRQ_HANDLED;
420 }
421
422 static irqreturn_t qproc_handover_interrupt(int irq, void *dev)
423 {
424         struct qproc *qproc = dev;
425
426         qproc_scm_clk_disable(qproc);
427         regulator_disable(qproc->pll);
428         return IRQ_HANDLED;
429 }
430
431 static irqreturn_t qproc_stop_ack_interrupt(int irq, void *dev)
432 {
433         struct qproc *qproc = dev;
434
435         complete(&qproc->stop_done);
436         return IRQ_HANDLED;
437 }
438
439 static ssize_t qproc_boot_store(struct device *dev,
440                                 struct device_attribute *attr,
441                                 const char *buf, size_t size)
442 {
443         struct qproc *qproc = dev_get_drvdata(dev);
444         int ret;
445
446         ret = rproc_boot(qproc->rproc);
447         return ret ? : size;
448 }
449
450 static ssize_t qproc_shutdown_store(struct device *dev,
451                                     struct device_attribute *attr,
452                                     const char *buf, size_t size)
453 {
454         struct qproc *qproc = dev_get_drvdata(dev);
455
456         rproc_shutdown(qproc->rproc);
457         return size;
458 }
459
460 static const struct device_attribute qproc_attrs[] = {
461         __ATTR(boot, S_IWUSR, 0, qproc_boot_store),
462         __ATTR(shutdown, S_IWUSR, 0, qproc_shutdown_store),
463 };
464
465 static int qproc_init_pas(struct qproc *qproc)
466 {
467         char *key;
468         int ret;
469
470         key = "qcom,pas-id";
471         ret = of_property_read_u32(qproc->dev->of_node, key, &qproc->pas_id);
472         if (ret) {
473                 dev_err(qproc->dev, "Missing or incorrect %s\n", key);
474                 return -EINVAL;
475         }
476
477         if (!qcom_scm_pas_supported(qproc->pas_id)) {
478                 dev_err(qproc->dev, "PAS is not available for %d\n", qproc->pas_id);
479                 return -EIO;
480         }
481
482         return 0;
483 }
484
485 static int qproc_init_clocks(struct qproc *qproc)
486 {
487         long rate;
488         int ret;
489
490         if (qproc->no_scm_clks)
491                 return 0;
492
493         qproc->scm_core_clk = devm_clk_get(qproc->dev, "scm_core_clk");
494         if (IS_ERR(qproc->scm_core_clk)) {
495                 if (PTR_ERR(qproc->scm_core_clk) != -EPROBE_DEFER)
496                         dev_err(qproc->dev, "failed to acquire scm_core_clk\n");
497                 return PTR_ERR(qproc->scm_core_clk);
498         }
499
500         qproc->scm_iface_clk = devm_clk_get(qproc->dev, "scm_iface_clk");
501         if (IS_ERR(qproc->scm_iface_clk)) {
502                 if (PTR_ERR(qproc->scm_iface_clk) != -EPROBE_DEFER)
503                         dev_err(qproc->dev, "failed to acquire scm_iface_clk\n");
504                 return PTR_ERR(qproc->scm_iface_clk);
505         }
506
507         qproc->scm_bus_clk = devm_clk_get(qproc->dev, "scm_bus_clk");
508         if (IS_ERR(qproc->scm_bus_clk)) {
509                 if (PTR_ERR(qproc->scm_bus_clk) != -EPROBE_DEFER)
510                         dev_err(qproc->dev, "failed to acquire scm_bus_clk\n");
511                 return PTR_ERR(qproc->scm_bus_clk);
512         }
513
514         qproc->scm_src_clk = devm_clk_get(qproc->dev, "scm_src_clk");
515         if (IS_ERR(qproc->scm_src_clk)) {
516                 if (PTR_ERR(qproc->scm_src_clk) != -EPROBE_DEFER)
517                         dev_err(qproc->dev, "failed to acquire scm_src_clk\n");
518                 return PTR_ERR(qproc->scm_src_clk);
519         }
520
521         ret = clk_set_rate(qproc->scm_core_clk,
522 clk_round_rate(qproc->scm_core_clk, 19200000));
523         ret = clk_set_rate(qproc->scm_bus_clk,
524 clk_round_rate(qproc->scm_bus_clk, 19200000));
525         ret = clk_set_rate(qproc->scm_iface_clk,
526 clk_round_rate(qproc->scm_iface_clk, 19200000));
527         rate = clk_round_rate(qproc->scm_core_clk, 80000000);
528         ret = clk_set_rate(qproc->scm_src_clk, rate);
529         if (ret) {
530                 dev_err(qproc->dev, "failed to set rate of scm_core_clk\n");
531                 return ret;
532         }
533
534         return 0;
535 }
536
537 static int qproc_init_regulators(struct qproc *qproc)
538 {
539         int ret;
540         u32 uA;
541         u32 uV;
542
543         qproc->pll = devm_regulator_get(qproc->dev, "qcom,pll");
544         if (IS_ERR(qproc->pll)) {
545                 if (PTR_ERR(qproc->pll) != -EPROBE_DEFER)
546                         dev_err(qproc->dev, "failed to aquire regulator\n");
547                 return PTR_ERR(qproc->pll);
548         }
549
550         ret = of_property_read_u32(qproc->dev->of_node, "qcom,pll-uV", &uV);
551         if (ret)
552                 dev_warn(qproc->dev, "failed to read qcom,pll_uV, skipping\n");
553         else
554                 regulator_set_voltage(qproc->pll, uV, uV);
555
556         ret = of_property_read_u32(qproc->dev->of_node, "qcom,pll-uA", &uA);
557         if (ret)
558                 dev_warn(qproc->dev, "failed to read qcom,pll_uA, skipping\n");
559         else
560                 regulator_set_load(qproc->pll, uA);
561
562         return 0;
563 }
564
565 static int qproc_request_irq(struct qproc *qproc, struct platform_device *pdev, const char *name, irq_handler_t thread_fn)
566 {
567         int ret;
568
569         ret = platform_get_irq_byname(pdev, name);
570         if (ret < 0) {
571                 dev_err(&pdev->dev, "no %s IRQ defined\n", name);
572                 return ret;
573         }
574
575         ret = devm_request_threaded_irq(&pdev->dev, ret,
576                                         NULL, thread_fn,
577                                         IRQF_TRIGGER_RISING | IRQF_ONESHOT,
578                                         "qproc", qproc);
579         if (ret)
580                 dev_err(&pdev->dev, "request %s IRQ failed\n", name);
581         return ret;
582 }
583
584 static int qproc_probe(struct platform_device *pdev)
585 {
586         struct qproc *qproc;
587         struct rproc *rproc;
588         char *fw_name;
589         const char *name;
590         const char *key;
591         int ret;
592         int i;
593         struct device_node *np;
594         struct resource r;
595
596
597         key = "qcom,firmware-name";
598         ret = of_property_read_string(pdev->dev.of_node, key, &name);
599         if (ret) {
600                 dev_err(&pdev->dev, "missing or incorrect %s\n", key);
601                 return -EINVAL;
602         }
603
604         fw_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s.mdt", name);
605         if (!fw_name)
606                 return -ENOMEM;
607
608         rproc = rproc_alloc(&pdev->dev, pdev->name, &qproc_ops,
609                             fw_name, sizeof(*qproc));
610         if (!rproc) {
611                 dev_err(&pdev->dev, "unable to allocate remoteproc\n");
612                 return -ENOMEM;
613         }
614
615         rproc->fw_ops = &qproc_fw_ops;
616
617         qproc = (struct qproc *)rproc->priv;
618         qproc->dev = &pdev->dev;
619         qproc->rproc = rproc;
620         qproc->name = name;
621         platform_set_drvdata(pdev, qproc);
622
623         init_completion(&qproc->start_done);
624         init_completion(&qproc->stop_done);
625
626         ret = of_property_read_u32(pdev->dev.of_node, "qcom,crash-reason",
627                                    &qproc->crash_reason);
628         if (ret)
629                 dev_info(&pdev->dev, "no crash reason id\n");
630
631         qproc->smd_edge_node = of_parse_phandle(pdev->dev.of_node,
632                                                 "qcom,smd-edges", 0);
633
634         qproc->no_scm_clks = of_device_is_compatible(pdev->dev.of_node,
635                                                      "qcom,apq8064-tz-pil");
636
637         ret = qproc_init_pas(qproc);
638         if (ret)
639                 goto free_rproc;
640
641         ret = qproc_init_clocks(qproc);
642         if (ret)
643                 goto free_rproc;
644
645         ret = qproc_init_regulators(qproc);
646         if (ret)
647                 goto free_rproc;
648
649         ret = qproc_request_irq(qproc, pdev, "wdog", qproc_wdog_interrupt);
650         qproc->wdog_irq = ret;
651
652         ret = qproc_request_irq(qproc, pdev, "fatal", qproc_fatal_interrupt);
653         qproc->fatal_irq = ret;
654
655         ret = qproc_request_irq(qproc, pdev, "ready", qproc_ready_interrupt);
656         qproc->ready_irq = ret;
657
658         ret = qproc_request_irq(qproc, pdev, "handover", qproc_handover_interrupt);
659         qproc->handover_irq = ret;
660
661         ret = qproc_request_irq(qproc, pdev, "stop-ack", qproc_stop_ack_interrupt);
662         qproc->stop_ack_irq = ret;
663
664         for (i = 0; i < ARRAY_SIZE(qproc_attrs); i++) {
665                 ret = device_create_file(&pdev->dev, &qproc_attrs[i]);
666                 if (ret) {
667                         dev_err(&pdev->dev, "unable to create sysfs file\n");
668                         goto remove_device_files;
669                 }
670         }
671
672         np = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
673         if (!np) {
674                 dev_err(&pdev->dev, "No memory region specified\n");
675         } else {
676
677                 ret = of_address_to_resource(np, 0, &r);
678                 of_node_put(np);
679                 if (ret)
680                         return ret;
681
682                 qproc->reloc_phys = r.start;
683                 qproc->reloc_size = resource_size(&r);
684
685                 dev_info(&pdev->dev, "Found relocation area %lu@%pad\n",
686                                 qproc->reloc_size, &qproc->reloc_phys);
687         }
688
689         ret = rproc_add(rproc);
690         if (ret)
691                 goto remove_device_files;
692
693         return 0;
694
695 remove_device_files:
696         for (i--; i >= 0; i--)
697                 device_remove_file(&pdev->dev, &qproc_attrs[i]);
698
699 free_rproc:
700         rproc_put(rproc);
701
702         return ret;
703 }
704
705 static int qproc_remove(struct platform_device *pdev)
706 {
707         struct qproc *qproc = platform_get_drvdata(pdev);
708         int i;
709
710         for (i = 0; i < ARRAY_SIZE(qproc_attrs); i++)
711                 device_remove_file(&pdev->dev, &qproc_attrs[i]);
712
713         rproc_put(qproc->rproc);
714
715         return 0;
716 }
717
718 static const struct of_device_id qproc_of_match[] = {
719         { .compatible = "qcom,tz-pil", },
720         { },
721 };
722
723 static struct platform_driver qproc_driver = {
724         .probe = qproc_probe,
725         .remove = qproc_remove,
726         .driver = {
727                 .name = "qcom-tz-pil",
728                 .of_match_table = qproc_of_match,
729         },
730 };
731
732 module_platform_driver(qproc_driver);