blob: 01b4790eeca351f327fa094b1b4ebeea0f0d4ca9 [file] [log] [blame]
Kyle Yan3d6600c2017-01-06 14:04:26 -08001/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
Kyle Yane45fa022016-08-29 11:40:26 -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/kernel.h>
14#include <linux/err.h>
15#include <linux/io.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/of.h>
19#include <linux/clk.h>
20#include <linux/regulator/consumer.h>
21#include <linux/interrupt.h>
22#include <linux/of_gpio.h>
23#include <linux/delay.h>
24
25#include <linux/msm-bus-board.h>
26#include <linux/msm-bus.h>
27#include <linux/dma-mapping.h>
28
29#include <soc/qcom/subsystem_restart.h>
30#include <soc/qcom/ramdump.h>
31#include <soc/qcom/scm.h>
32
33#include <soc/qcom/smem.h>
34
35#include "peripheral-loader.h"
36
37#define XO_FREQ 19200000
38#define PROXY_TIMEOUT_MS 10000
Kyle Yanfe3813e2017-06-06 17:03:58 -070039#define MAX_SSR_REASON_LEN 256U
Kyle Yane45fa022016-08-29 11:40:26 -070040#define STOP_ACK_TIMEOUT_MS 1000
41#define CRASH_STOP_ACK_TO_MS 200
42
43#define ERR_READY 0
44#define PBL_DONE 1
Avaneesh Kumar Dwivedi94619d92017-10-05 17:58:38 +053045#define QDSP6SS_NMI_STATUS 0x44
Kyle Yane45fa022016-08-29 11:40:26 -070046
47#define desc_to_data(d) container_of(d, struct pil_tz_data, desc)
48#define subsys_to_data(d) container_of(d, struct pil_tz_data, subsys_desc)
49
50/**
51 * struct reg_info - regulator info
52 * @reg: regulator handle
53 * @uV: voltage in uV
54 * @uA: current in uA
55 */
56struct reg_info {
57 struct regulator *reg;
58 int uV;
59 int uA;
60};
61
62/**
63 * struct pil_tz_data
64 * @regs: regulators that should be always on when the subsystem is
65 * brought out of reset
66 * @proxy_regs: regulators that should be on during pil proxy voting
67 * @clks: clocks that should be always on when the subsystem is
68 * brought out of reset
69 * @proxy_clks: clocks that should be on during pil proxy voting
70 * @reg_count: the number of always on regulators
71 * @proxy_reg_count: the number of proxy voting regulators
72 * @clk_count: the number of always on clocks
73 * @proxy_clk_count: the number of proxy voting clocks
74 * @smem_id: the smem id used for read the subsystem crash reason
75 * @ramdump_dev: ramdump device pointer
76 * @pas_id: the PAS id for tz
77 * @bus_client: bus client id
78 * @enable_bus_scaling: set to true if PIL needs to vote for
79 * bus bandwidth
80 * @keep_proxy_regs_on: If set, during proxy unvoting, PIL removes the
81 * voltage/current vote for proxy regulators but leaves
82 * them enabled.
83 * @stop_ack: state of completion of stop ack
84 * @desc: PIL descriptor
85 * @subsys: subsystem device pointer
86 * @subsys_desc: subsystem descriptor
87 * @u32 bits_arr[2]: array of bit positions in SCSR registers
88 */
89struct pil_tz_data {
90 struct reg_info *regs;
91 struct reg_info *proxy_regs;
92 struct clk **clks;
93 struct clk **proxy_clks;
94 int reg_count;
95 int proxy_reg_count;
96 int clk_count;
97 int proxy_clk_count;
98 int smem_id;
99 void *ramdump_dev;
100 u32 pas_id;
101 u32 bus_client;
102 bool enable_bus_scaling;
103 bool keep_proxy_regs_on;
104 struct completion stop_ack;
105 struct pil_desc desc;
106 struct subsys_device *subsys;
107 struct subsys_desc subsys_desc;
108 void __iomem *irq_status;
109 void __iomem *irq_clear;
110 void __iomem *irq_mask;
111 void __iomem *err_status;
112 void __iomem *err_status_spare;
Avaneesh Kumar Dwivedi94619d92017-10-05 17:58:38 +0530113 void __iomem *reg_base;
Kyle Yane45fa022016-08-29 11:40:26 -0700114 u32 bits_arr[2];
115};
116
117enum scm_cmd {
118 PAS_INIT_IMAGE_CMD = 1,
119 PAS_MEM_SETUP_CMD,
120 PAS_AUTH_AND_RESET_CMD = 5,
121 PAS_SHUTDOWN_CMD,
122};
123
124enum pas_id {
125 PAS_MODEM,
126 PAS_Q6,
127 PAS_DSPS,
128 PAS_TZAPPS,
129 PAS_MODEM_SW,
130 PAS_MODEM_FW,
131 PAS_WCNSS,
132 PAS_SECAPP,
133 PAS_GSS,
134 PAS_VIDC,
135 PAS_VPU,
136 PAS_BCSS,
137};
138
139static struct msm_bus_paths scm_pas_bw_tbl[] = {
140 {
141 .vectors = (struct msm_bus_vectors[]){
142 {
143 .src = MSM_BUS_MASTER_SPS,
144 .dst = MSM_BUS_SLAVE_EBI_CH0,
145 },
146 },
147 .num_paths = 1,
148 },
149 {
150 .vectors = (struct msm_bus_vectors[]){
151 {
152 .src = MSM_BUS_MASTER_SPS,
153 .dst = MSM_BUS_SLAVE_EBI_CH0,
154 .ib = 492 * 8 * 1000000UL,
155 .ab = 492 * 8 * 100000UL,
156 },
157 },
158 .num_paths = 1,
159 },
160};
161
162static struct msm_bus_scale_pdata scm_pas_bus_pdata = {
163 .usecase = scm_pas_bw_tbl,
164 .num_usecases = ARRAY_SIZE(scm_pas_bw_tbl),
165 .name = "scm_pas",
166};
167
168static uint32_t scm_perf_client;
169static int scm_pas_bw_count;
170static DEFINE_MUTEX(scm_pas_bw_mutex);
171
172static int scm_pas_enable_bw(void)
173{
174 int ret = 0;
175
176 if (!scm_perf_client)
177 return -EINVAL;
178
179 mutex_lock(&scm_pas_bw_mutex);
180 if (!scm_pas_bw_count) {
181 ret = msm_bus_scale_client_update_request(scm_perf_client, 1);
182 if (ret)
183 goto err_bus;
184 scm_pas_bw_count++;
185 }
186
187 mutex_unlock(&scm_pas_bw_mutex);
188 return ret;
189
190err_bus:
191 pr_err("scm-pas; Bandwidth request failed (%d)\n", ret);
192 msm_bus_scale_client_update_request(scm_perf_client, 0);
193
194 mutex_unlock(&scm_pas_bw_mutex);
195 return ret;
196}
197
198static void scm_pas_disable_bw(void)
199{
200 mutex_lock(&scm_pas_bw_mutex);
201 if (scm_pas_bw_count-- == 1)
202 msm_bus_scale_client_update_request(scm_perf_client, 0);
203 mutex_unlock(&scm_pas_bw_mutex);
204}
205
206static void scm_pas_init(int id)
207{
208 static int is_inited;
209
210 if (is_inited)
211 return;
212
213 scm_pas_bw_tbl[0].vectors[0].src = id;
214 scm_pas_bw_tbl[1].vectors[0].src = id;
215
216 scm_perf_client = msm_bus_scale_register_client(&scm_pas_bus_pdata);
217 if (!scm_perf_client)
218 pr_warn("scm-pas: Unable to register bus client\n");
219
220 is_inited = 1;
221}
222
223static int of_read_clocks(struct device *dev, struct clk ***clks_ref,
224 const char *propname)
225{
226 long clk_count;
227 int i, len;
228 struct clk **clks;
229
230 if (!of_find_property(dev->of_node, propname, &len))
231 return 0;
232
233 clk_count = of_property_count_strings(dev->of_node, propname);
234 if (IS_ERR_VALUE(clk_count)) {
235 dev_err(dev, "Failed to get clock names\n");
236 return -EINVAL;
237 }
238
239 clks = devm_kzalloc(dev, sizeof(struct clk *) * clk_count,
240 GFP_KERNEL);
241 if (!clks)
242 return -ENOMEM;
243
244 for (i = 0; i < clk_count; i++) {
245 const char *clock_name;
246 char clock_freq_name[50];
247 u32 clock_rate = XO_FREQ;
248
249 of_property_read_string_index(dev->of_node,
250 propname, i,
251 &clock_name);
252 snprintf(clock_freq_name, ARRAY_SIZE(clock_freq_name),
253 "qcom,%s-freq", clock_name);
254 if (of_find_property(dev->of_node, clock_freq_name, &len))
255 if (of_property_read_u32(dev->of_node, clock_freq_name,
256 &clock_rate)) {
257 dev_err(dev, "Failed to read %s clock's freq\n",
258 clock_freq_name);
259 return -EINVAL;
260 }
261
262 clks[i] = devm_clk_get(dev, clock_name);
263 if (IS_ERR(clks[i])) {
264 int rc = PTR_ERR(clks[i]);
265
266 if (rc != -EPROBE_DEFER)
267 dev_err(dev, "Failed to get %s clock\n",
268 clock_name);
269 return rc;
270 }
271
272 /* Make sure rate-settable clocks' rates are set */
273 if (clk_get_rate(clks[i]) == 0)
274 clk_set_rate(clks[i], clk_round_rate(clks[i],
275 clock_rate));
276 }
277
278 *clks_ref = clks;
279 return clk_count;
280}
281
282static int of_read_regs(struct device *dev, struct reg_info **regs_ref,
283 const char *propname)
284{
285 long reg_count;
286 int i, len, rc;
287 struct reg_info *regs;
288
289 if (!of_find_property(dev->of_node, propname, &len))
290 return 0;
291
292 reg_count = of_property_count_strings(dev->of_node, propname);
293 if (IS_ERR_VALUE(reg_count)) {
294 dev_err(dev, "Failed to get regulator names\n");
295 return -EINVAL;
296 }
297
298 regs = devm_kzalloc(dev, sizeof(struct reg_info) * reg_count,
299 GFP_KERNEL);
300 if (!regs)
301 return -ENOMEM;
302
303 for (i = 0; i < reg_count; i++) {
304 const char *reg_name;
305 char reg_uV_uA_name[50];
306 u32 vdd_uV_uA[2];
307
308 of_property_read_string_index(dev->of_node,
309 propname, i,
310 &reg_name);
311
312 regs[i].reg = devm_regulator_get(dev, reg_name);
313 if (IS_ERR(regs[i].reg)) {
314 int rc = PTR_ERR(regs[i].reg);
315
316 if (rc != -EPROBE_DEFER)
317 dev_err(dev, "Failed to get %s\n regulator",
318 reg_name);
319 return rc;
320 }
321
322 /*
323 * Read the voltage and current values for the corresponding
324 * regulator. The device tree property name is "qcom," +
325 * "regulator_name" + "-uV-uA".
326 */
327 rc = snprintf(reg_uV_uA_name, ARRAY_SIZE(reg_uV_uA_name),
328 "qcom,%s-uV-uA", reg_name);
329 if (rc < strlen(reg_name) + 6) {
330 dev_err(dev, "Failed to hold reg_uV_uA_name\n");
331 return -EINVAL;
332 }
333
334 if (!of_find_property(dev->of_node, reg_uV_uA_name, &len))
335 continue;
336
337 len /= sizeof(vdd_uV_uA[0]);
338
339 /* There should be two entries: one for uV and one for uA */
340 if (len != 2) {
341 dev_err(dev, "Missing uV/uA value\n");
342 return -EINVAL;
343 }
344
345 rc = of_property_read_u32_array(dev->of_node, reg_uV_uA_name,
346 vdd_uV_uA, len);
347 if (rc) {
348 dev_err(dev, "Failed to read uV/uA values(rc:%d)\n",
349 rc);
350 return rc;
351 }
352
353 regs[i].uV = vdd_uV_uA[0];
354 regs[i].uA = vdd_uV_uA[1];
355 }
356
357 *regs_ref = regs;
358 return reg_count;
359}
360
361static int of_read_bus_pdata(struct platform_device *pdev,
362 struct pil_tz_data *d)
363{
364 struct msm_bus_scale_pdata *pdata;
365
366 pdata = msm_bus_cl_get_pdata(pdev);
367
368 if (!pdata)
369 return -EINVAL;
370
371 d->bus_client = msm_bus_scale_register_client(pdata);
372 if (!d->bus_client)
373 pr_warn("%s: Unable to register bus client\n", __func__);
374
375 return 0;
376}
377
378static int piltz_resc_init(struct platform_device *pdev, struct pil_tz_data *d)
379{
380 int len, count, rc;
381 struct device *dev = &pdev->dev;
382
383 count = of_read_clocks(dev, &d->clks, "qcom,active-clock-names");
384 if (count < 0) {
385 dev_err(dev, "Failed to setup clocks.\n");
386 return count;
387 }
388 d->clk_count = count;
389
390 count = of_read_clocks(dev, &d->proxy_clks, "qcom,proxy-clock-names");
391 if (count < 0) {
392 dev_err(dev, "Failed to setup proxy clocks.\n");
393 return count;
394 }
395 d->proxy_clk_count = count;
396
397 count = of_read_regs(dev, &d->regs, "qcom,active-reg-names");
398 if (count < 0) {
399 dev_err(dev, "Failed to setup regulators.\n");
400 return count;
401 }
402 d->reg_count = count;
403
404 count = of_read_regs(dev, &d->proxy_regs, "qcom,proxy-reg-names");
405 if (count < 0) {
406 dev_err(dev, "Failed to setup proxy regulators.\n");
407 return count;
408 }
409 d->proxy_reg_count = count;
410
411 if (of_find_property(dev->of_node, "qcom,msm-bus,name", &len)) {
412 d->enable_bus_scaling = true;
413 rc = of_read_bus_pdata(pdev, d);
414 if (rc) {
415 dev_err(dev, "Failed to setup bus scaling client.\n");
416 return rc;
417 }
418 }
419
420 return 0;
421}
422
423static int enable_regulators(struct pil_tz_data *d, struct device *dev,
424 struct reg_info *regs, int reg_count,
425 bool reg_no_enable)
426{
427 int i, rc = 0;
428
429 for (i = 0; i < reg_count; i++) {
430 if (regs[i].uV > 0) {
431 rc = regulator_set_voltage(regs[i].reg,
432 regs[i].uV, INT_MAX);
433 if (rc) {
434 dev_err(dev, "Failed to request voltage(rc:%d)\n",
435 rc);
436 goto err_voltage;
437 }
438 }
439
440 if (regs[i].uA > 0) {
441 rc = regulator_set_load(regs[i].reg,
442 regs[i].uA);
443 if (rc < 0) {
444 dev_err(dev, "Failed to set regulator mode(rc:%d)\n",
445 rc);
446 goto err_mode;
447 }
448 }
449
450 if (d->keep_proxy_regs_on && reg_no_enable)
451 continue;
452
453 rc = regulator_enable(regs[i].reg);
454 if (rc) {
455 dev_err(dev, "Regulator enable failed(rc:%d)\n", rc);
456 goto err_enable;
457 }
458 }
459
460 return 0;
461err_enable:
462 if (regs[i].uA > 0) {
463 regulator_set_voltage(regs[i].reg, 0, INT_MAX);
464 regulator_set_load(regs[i].reg, 0);
465 }
466err_mode:
467 if (regs[i].uV > 0)
468 regulator_set_voltage(regs[i].reg, 0, INT_MAX);
469err_voltage:
470 for (i--; i >= 0; i--) {
471 if (regs[i].uV > 0)
472 regulator_set_voltage(regs[i].reg, 0, INT_MAX);
473
474 if (regs[i].uA > 0)
475 regulator_set_load(regs[i].reg, 0);
476
477 if (d->keep_proxy_regs_on && reg_no_enable)
478 continue;
479 regulator_disable(regs[i].reg);
480 }
481
482 return rc;
483}
484
485static void disable_regulators(struct pil_tz_data *d, struct reg_info *regs,
486 int reg_count, bool reg_no_disable)
487{
488 int i;
489
490 for (i = 0; i < reg_count; i++) {
491 if (regs[i].uV > 0)
492 regulator_set_voltage(regs[i].reg, 0, INT_MAX);
493
494 if (regs[i].uA > 0)
495 regulator_set_load(regs[i].reg, 0);
496
497 if (d->keep_proxy_regs_on && reg_no_disable)
498 continue;
499 regulator_disable(regs[i].reg);
500 }
501}
502
503static int prepare_enable_clocks(struct device *dev, struct clk **clks,
504 int clk_count)
505{
506 int rc = 0;
507 int i;
508
509 for (i = 0; i < clk_count; i++) {
510 rc = clk_prepare_enable(clks[i]);
511 if (rc) {
512 dev_err(dev, "Clock enable failed(rc:%d)\n", rc);
513 goto err;
514 }
515 }
516
517 return 0;
518err:
519 for (i--; i >= 0; i--)
520 clk_disable_unprepare(clks[i]);
521
522 return rc;
523}
524
525static void disable_unprepare_clocks(struct clk **clks, int clk_count)
526{
527 int i;
528
529 for (i = --clk_count; i >= 0; i--)
530 clk_disable_unprepare(clks[i]);
531}
532
533static int pil_make_proxy_vote(struct pil_desc *pil)
534{
535 struct pil_tz_data *d = desc_to_data(pil);
536 int rc;
537
538 if (d->subsys_desc.no_auth)
539 return 0;
540
Kyle Yanf995ef62017-04-13 19:13:39 -0700541 if (d->bus_client) {
542 rc = msm_bus_scale_client_update_request(d->bus_client, 1);
543 if (rc) {
544 dev_err(pil->dev, "bandwidth request failed(rc:%d)\n",
545 rc);
546 return rc;
547 }
548 } else
549 WARN(d->enable_bus_scaling, "Bus scaling not set up for %s!\n",
550 d->subsys_desc.name);
551
Kyle Yane45fa022016-08-29 11:40:26 -0700552 rc = enable_regulators(d, pil->dev, d->proxy_regs,
553 d->proxy_reg_count, false);
554 if (rc)
555 return rc;
556
557 rc = prepare_enable_clocks(pil->dev, d->proxy_clks,
558 d->proxy_clk_count);
559 if (rc)
560 goto err_clks;
561
Kyle Yane45fa022016-08-29 11:40:26 -0700562 return 0;
Kyle Yanf995ef62017-04-13 19:13:39 -0700563
Kyle Yane45fa022016-08-29 11:40:26 -0700564err_clks:
565 disable_regulators(d, d->proxy_regs, d->proxy_reg_count, false);
566
567 return rc;
568}
569
570static void pil_remove_proxy_vote(struct pil_desc *pil)
571{
572 struct pil_tz_data *d = desc_to_data(pil);
573
574 if (d->subsys_desc.no_auth)
575 return;
576
Kyle Yanf995ef62017-04-13 19:13:39 -0700577 disable_unprepare_clocks(d->proxy_clks, d->proxy_clk_count);
578
579 disable_regulators(d, d->proxy_regs, d->proxy_reg_count, true);
580
Kyle Yane45fa022016-08-29 11:40:26 -0700581 if (d->bus_client)
582 msm_bus_scale_client_update_request(d->bus_client, 0);
583 else
584 WARN(d->enable_bus_scaling, "Bus scaling not set up for %s!\n",
585 d->subsys_desc.name);
Kyle Yane45fa022016-08-29 11:40:26 -0700586}
587
588static int pil_init_image_trusted(struct pil_desc *pil,
589 const u8 *metadata, size_t size)
590{
591 struct pil_tz_data *d = desc_to_data(pil);
592 struct pas_init_image_req {
593 u32 proc;
594 u32 image_addr;
595 } request;
596 u32 scm_ret = 0;
597 void *mdata_buf;
598 dma_addr_t mdata_phys;
599 int ret;
600 unsigned long attrs = 0;
601 struct device dev = {0};
602 struct scm_desc desc = {0};
603
604 if (d->subsys_desc.no_auth)
605 return 0;
606
607 ret = scm_pas_enable_bw();
608 if (ret)
609 return ret;
610 arch_setup_dma_ops(&dev, 0, 0, NULL, 0);
611
612 dev.coherent_dma_mask =
613 DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
614 attrs |= DMA_ATTR_STRONGLY_ORDERED;
615 mdata_buf = dma_alloc_attrs(&dev, size, &mdata_phys, GFP_KERNEL,
616 attrs);
617 if (!mdata_buf) {
618 pr_err("scm-pas: Allocation for metadata failed.\n");
619 scm_pas_disable_bw();
620 return -ENOMEM;
621 }
622
623 memcpy(mdata_buf, metadata, size);
624
625 request.proc = d->pas_id;
626 request.image_addr = mdata_phys;
627
628 if (!is_scm_armv8()) {
629 ret = scm_call(SCM_SVC_PIL, PAS_INIT_IMAGE_CMD, &request,
630 sizeof(request), &scm_ret, sizeof(scm_ret));
631 } else {
632 desc.args[0] = d->pas_id;
633 desc.args[1] = mdata_phys;
634 desc.arginfo = SCM_ARGS(2, SCM_VAL, SCM_RW);
635 ret = scm_call2(SCM_SIP_FNID(SCM_SVC_PIL, PAS_INIT_IMAGE_CMD),
636 &desc);
637 scm_ret = desc.ret[0];
638 }
639
640 dma_free_attrs(&dev, size, mdata_buf, mdata_phys, attrs);
641 scm_pas_disable_bw();
642 if (ret)
643 return ret;
644 return scm_ret;
645}
646
647static int pil_mem_setup_trusted(struct pil_desc *pil, phys_addr_t addr,
648 size_t size)
649{
650 struct pil_tz_data *d = desc_to_data(pil);
651 struct pas_init_image_req {
652 u32 proc;
653 u32 start_addr;
654 u32 len;
655 } request;
656 u32 scm_ret = 0;
657 int ret;
658 struct scm_desc desc = {0};
659
660 if (d->subsys_desc.no_auth)
661 return 0;
662
663 request.proc = d->pas_id;
664 request.start_addr = addr;
665 request.len = size;
666
667 if (!is_scm_armv8()) {
668 ret = scm_call(SCM_SVC_PIL, PAS_MEM_SETUP_CMD, &request,
669 sizeof(request), &scm_ret, sizeof(scm_ret));
670 } else {
671 desc.args[0] = d->pas_id;
672 desc.args[1] = addr;
673 desc.args[2] = size;
674 desc.arginfo = SCM_ARGS(3);
675 ret = scm_call2(SCM_SIP_FNID(SCM_SVC_PIL, PAS_MEM_SETUP_CMD),
676 &desc);
677 scm_ret = desc.ret[0];
678 }
679 if (ret)
680 return ret;
681 return scm_ret;
682}
683
684static int pil_auth_and_reset(struct pil_desc *pil)
685{
686 struct pil_tz_data *d = desc_to_data(pil);
687 int rc;
688 u32 proc, scm_ret = 0;
689 struct scm_desc desc = {0};
690
691 if (d->subsys_desc.no_auth)
692 return 0;
693
694 desc.args[0] = proc = d->pas_id;
695 desc.arginfo = SCM_ARGS(1);
696
Kyle Yanf995ef62017-04-13 19:13:39 -0700697 rc = scm_pas_enable_bw();
698 if (rc)
699 return rc;
700
Kyle Yane45fa022016-08-29 11:40:26 -0700701 rc = enable_regulators(d, pil->dev, d->regs, d->reg_count, false);
702 if (rc)
703 return rc;
704
705 rc = prepare_enable_clocks(pil->dev, d->clks, d->clk_count);
706 if (rc)
707 goto err_clks;
708
Kyle Yane45fa022016-08-29 11:40:26 -0700709 if (!is_scm_armv8()) {
710 rc = scm_call(SCM_SVC_PIL, PAS_AUTH_AND_RESET_CMD, &proc,
711 sizeof(proc), &scm_ret, sizeof(scm_ret));
712 } else {
713 rc = scm_call2(SCM_SIP_FNID(SCM_SVC_PIL,
714 PAS_AUTH_AND_RESET_CMD), &desc);
715 scm_ret = desc.ret[0];
716 }
717 scm_pas_disable_bw();
718 if (rc)
719 goto err_reset;
720
721 return scm_ret;
722err_reset:
723 disable_unprepare_clocks(d->clks, d->clk_count);
724err_clks:
725 disable_regulators(d, d->regs, d->reg_count, false);
726
727 return rc;
728}
729
730static int pil_shutdown_trusted(struct pil_desc *pil)
731{
732 struct pil_tz_data *d = desc_to_data(pil);
733 u32 proc, scm_ret = 0;
734 int rc;
735 struct scm_desc desc = {0};
736
737 if (d->subsys_desc.no_auth)
738 return 0;
739
740 desc.args[0] = proc = d->pas_id;
741 desc.arginfo = SCM_ARGS(1);
742
Kyle Yan5cb0e082017-04-21 18:13:25 -0700743 if (d->bus_client) {
744 rc = msm_bus_scale_client_update_request(d->bus_client, 1);
745 if (rc) {
746 dev_err(pil->dev, "bandwidth request failed(rc:%d)\n",
747 rc);
748 return rc;
749 }
750 } else
751 WARN(d->enable_bus_scaling, "Bus scaling not set up for %s!\n",
752 d->subsys_desc.name);
753
Kyle Yane45fa022016-08-29 11:40:26 -0700754 rc = enable_regulators(d, pil->dev, d->proxy_regs,
755 d->proxy_reg_count, true);
756 if (rc)
Kyle Yan5cb0e082017-04-21 18:13:25 -0700757 goto err_regulators;
Kyle Yane45fa022016-08-29 11:40:26 -0700758
759 rc = prepare_enable_clocks(pil->dev, d->proxy_clks,
760 d->proxy_clk_count);
761 if (rc)
762 goto err_clks;
763
764 if (!is_scm_armv8()) {
765 rc = scm_call(SCM_SVC_PIL, PAS_SHUTDOWN_CMD, &proc,
766 sizeof(proc), &scm_ret, sizeof(scm_ret));
767 } else {
768 rc = scm_call2(SCM_SIP_FNID(SCM_SVC_PIL, PAS_SHUTDOWN_CMD),
769 &desc);
770 scm_ret = desc.ret[0];
771 }
772
773 disable_unprepare_clocks(d->proxy_clks, d->proxy_clk_count);
774 disable_regulators(d, d->proxy_regs, d->proxy_reg_count, false);
Kyle Yan5cb0e082017-04-21 18:13:25 -0700775 if (d->bus_client)
776 msm_bus_scale_client_update_request(d->bus_client, 0);
777 else
778 WARN(d->enable_bus_scaling, "Bus scaling not set up for %s!\n",
779 d->subsys_desc.name);
Kyle Yane45fa022016-08-29 11:40:26 -0700780
781 if (rc)
782 return rc;
783
784 disable_unprepare_clocks(d->clks, d->clk_count);
785 disable_regulators(d, d->regs, d->reg_count, false);
786
787 return scm_ret;
Kyle Yan5cb0e082017-04-21 18:13:25 -0700788
Kyle Yane45fa022016-08-29 11:40:26 -0700789err_clks:
790 disable_regulators(d, d->proxy_regs, d->proxy_reg_count, false);
Kyle Yan5cb0e082017-04-21 18:13:25 -0700791err_regulators:
792 if (d->bus_client)
793 msm_bus_scale_client_update_request(d->bus_client, 0);
794 else
795 WARN(d->enable_bus_scaling, "Bus scaling not set up for %s!\n",
796 d->subsys_desc.name);
Kyle Yane45fa022016-08-29 11:40:26 -0700797 return rc;
798}
799
Kyle Yan5ea38952017-08-03 16:05:55 -0700800static int pil_deinit_image_trusted(struct pil_desc *pil)
801{
802 struct pil_tz_data *d = desc_to_data(pil);
803 u32 proc, scm_ret = 0;
804 int rc;
805 struct scm_desc desc = {0};
806
807 if (d->subsys_desc.no_auth)
808 return 0;
809
810 desc.args[0] = proc = d->pas_id;
811 desc.arginfo = SCM_ARGS(1);
812
813 if (!is_scm_armv8()) {
814 rc = scm_call(SCM_SVC_PIL, PAS_SHUTDOWN_CMD, &proc,
815 sizeof(proc), &scm_ret, sizeof(scm_ret));
816 } else {
817 rc = scm_call2(SCM_SIP_FNID(SCM_SVC_PIL, PAS_SHUTDOWN_CMD),
818 &desc);
819 scm_ret = desc.ret[0];
820 }
821
822 if (rc)
823 return rc;
824 return scm_ret;
825}
826
Kyle Yane45fa022016-08-29 11:40:26 -0700827static struct pil_reset_ops pil_ops_trusted = {
828 .init_image = pil_init_image_trusted,
829 .mem_setup = pil_mem_setup_trusted,
830 .auth_and_reset = pil_auth_and_reset,
831 .shutdown = pil_shutdown_trusted,
832 .proxy_vote = pil_make_proxy_vote,
833 .proxy_unvote = pil_remove_proxy_vote,
Kyle Yan5ea38952017-08-03 16:05:55 -0700834 .deinit_image = pil_deinit_image_trusted,
Kyle Yane45fa022016-08-29 11:40:26 -0700835};
836
837static void log_failure_reason(const struct pil_tz_data *d)
838{
839 u32 size;
840 char *smem_reason, reason[MAX_SSR_REASON_LEN];
841 const char *name = d->subsys_desc.name;
842
843 if (d->smem_id == -1)
844 return;
845
846 smem_reason = smem_get_entry_no_rlock(d->smem_id, &size, 0,
847 SMEM_ANY_HOST_FLAG);
848 if (!smem_reason || !size) {
849 pr_err("%s SFR: (unknown, smem_get_entry_no_rlock failed).\n",
850 name);
851 return;
852 }
853 if (!smem_reason[0]) {
854 pr_err("%s SFR: (unknown, empty string found).\n", name);
855 return;
856 }
857
858 strlcpy(reason, smem_reason, min(size, MAX_SSR_REASON_LEN));
859 pr_err("%s subsystem failure reason: %s.\n", name, reason);
Kyle Yane45fa022016-08-29 11:40:26 -0700860}
861
862static int subsys_shutdown(const struct subsys_desc *subsys, bool force_stop)
863{
864 struct pil_tz_data *d = subsys_to_data(subsys);
865 int ret;
866
867 if (!subsys_get_crash_status(d->subsys) && force_stop &&
868 subsys->force_stop_gpio) {
869 gpio_set_value(subsys->force_stop_gpio, 1);
870 ret = wait_for_completion_timeout(&d->stop_ack,
871 msecs_to_jiffies(STOP_ACK_TIMEOUT_MS));
872 if (!ret)
873 pr_warn("Timed out on stop ack from %s.\n",
874 subsys->name);
875 gpio_set_value(subsys->force_stop_gpio, 0);
876 }
877
878 pil_shutdown(&d->desc);
879 return 0;
880}
881
882static int subsys_powerup(const struct subsys_desc *subsys)
883{
884 struct pil_tz_data *d = subsys_to_data(subsys);
885 int ret = 0;
886
887 if (subsys->stop_ack_irq)
888 reinit_completion(&d->stop_ack);
889
890 d->desc.fw_name = subsys->fw_name;
891 ret = pil_boot(&d->desc);
892
893 return ret;
894}
895
896static int subsys_ramdump(int enable, const struct subsys_desc *subsys)
897{
898 struct pil_tz_data *d = subsys_to_data(subsys);
899
900 if (!enable)
901 return 0;
902
903 return pil_do_ramdump(&d->desc, d->ramdump_dev);
904}
905
906static void subsys_free_memory(const struct subsys_desc *subsys)
907{
908 struct pil_tz_data *d = subsys_to_data(subsys);
909
910 pil_free_memory(&d->desc);
911}
912
913static void subsys_crash_shutdown(const struct subsys_desc *subsys)
914{
915 struct pil_tz_data *d = subsys_to_data(subsys);
916
917 if (subsys->force_stop_gpio > 0 &&
918 !subsys_get_crash_status(d->subsys)) {
919 gpio_set_value(subsys->force_stop_gpio, 1);
920 mdelay(CRASH_STOP_ACK_TO_MS);
921 }
922}
923
924static irqreturn_t subsys_err_fatal_intr_handler (int irq, void *dev_id)
925{
926 struct pil_tz_data *d = subsys_to_data(dev_id);
Avaneesh Kumar Dwivedi94619d92017-10-05 17:58:38 +0530927 u32 nmi_status = 0;
Kyle Yane45fa022016-08-29 11:40:26 -0700928
Avaneesh Kumar Dwivedi94619d92017-10-05 17:58:38 +0530929 if (d->reg_base)
930 nmi_status = readl_relaxed(d->reg_base +
931 QDSP6SS_NMI_STATUS);
932
933 if (nmi_status & 0x04)
934 pr_err("%s: Fatal error on the %s due to TZ NMI\n",
935 __func__, d->subsys_desc.name);
936 else
937 pr_err("%s Fatal error on the %s\n",
938 __func__, d->subsys_desc.name);
939
Kyle Yane45fa022016-08-29 11:40:26 -0700940 if (subsys_get_crash_status(d->subsys)) {
941 pr_err("%s: Ignoring error fatal, restart in progress\n",
942 d->subsys_desc.name);
943 return IRQ_HANDLED;
944 }
Satya Durga Srinivasu Prabhala30af7d02016-12-15 13:33:39 -0800945 subsys_set_crash_status(d->subsys, CRASH_STATUS_ERR_FATAL);
Kyle Yane45fa022016-08-29 11:40:26 -0700946 log_failure_reason(d);
947 subsystem_restart_dev(d->subsys);
948
949 return IRQ_HANDLED;
950}
951
952static irqreturn_t subsys_wdog_bite_irq_handler(int irq, void *dev_id)
953{
954 struct pil_tz_data *d = subsys_to_data(dev_id);
955
956 if (subsys_get_crash_status(d->subsys))
957 return IRQ_HANDLED;
958 pr_err("Watchdog bite received from %s!\n", d->subsys_desc.name);
959
960 if (d->subsys_desc.system_debug &&
961 !gpio_get_value(d->subsys_desc.err_fatal_gpio))
962 panic("%s: System ramdump requested. Triggering device restart!\n",
963 __func__);
Satya Durga Srinivasu Prabhala30af7d02016-12-15 13:33:39 -0800964 subsys_set_crash_status(d->subsys, CRASH_STATUS_WDOG_BITE);
Kyle Yane45fa022016-08-29 11:40:26 -0700965 log_failure_reason(d);
966 subsystem_restart_dev(d->subsys);
967
968 return IRQ_HANDLED;
969}
970
971static irqreturn_t subsys_stop_ack_intr_handler(int irq, void *dev_id)
972{
973 struct pil_tz_data *d = subsys_to_data(dev_id);
974
975 pr_info("Received stop ack interrupt from %s\n", d->subsys_desc.name);
976 complete(&d->stop_ack);
977 return IRQ_HANDLED;
978}
979
Puja Gupta557f5292016-11-28 14:01:03 -0800980static void clear_pbl_done(struct pil_tz_data *d)
Kyle Yane45fa022016-08-29 11:40:26 -0700981{
982 uint32_t err_value;
983
984 err_value = __raw_readl(d->err_status);
985 pr_debug("PBL_DONE received from %s!\n", d->subsys_desc.name);
986 if (err_value) {
987 uint32_t rmb_err_spare0;
988 uint32_t rmb_err_spare1;
989 uint32_t rmb_err_spare2;
990
991 rmb_err_spare2 = __raw_readl(d->err_status_spare);
992 rmb_err_spare1 = __raw_readl(d->err_status_spare-4);
993 rmb_err_spare0 = __raw_readl(d->err_status_spare-8);
994
995 pr_err("PBL error status register: 0x%08x\n", err_value);
996
997 pr_err("PBL error status spare0 register: 0x%08x\n",
998 rmb_err_spare0);
999 pr_err("PBL error status spare1 register: 0x%08x\n",
1000 rmb_err_spare1);
1001 pr_err("PBL error status spare2 register: 0x%08x\n",
1002 rmb_err_spare2);
1003 }
1004 __raw_writel(BIT(d->bits_arr[PBL_DONE]), d->irq_clear);
1005}
1006
Puja Gupta557f5292016-11-28 14:01:03 -08001007static void clear_err_ready(struct pil_tz_data *d)
Kyle Yane45fa022016-08-29 11:40:26 -07001008{
Puja Gupta557f5292016-11-28 14:01:03 -08001009 pr_debug("Subsystem error services up received from %s\n",
Kyle Yane45fa022016-08-29 11:40:26 -07001010 d->subsys_desc.name);
Puja Gupta557f5292016-11-28 14:01:03 -08001011 __raw_writel(BIT(d->bits_arr[ERR_READY]), d->irq_clear);
1012 complete_err_ready(d->subsys);
1013}
1014
1015static void clear_wdog(struct pil_tz_data *d)
1016{
1017 /* Check crash status to know if device is restarting*/
1018 if (!subsys_get_crash_status(d->subsys)) {
Kyle Yane45fa022016-08-29 11:40:26 -07001019 pr_err("wdog bite received from %s!\n", d->subsys_desc.name);
1020 __raw_writel(BIT(d->bits_arr[ERR_READY]), d->irq_clear);
Satya Durga Srinivasu Prabhala30af7d02016-12-15 13:33:39 -08001021 subsys_set_crash_status(d->subsys, CRASH_STATUS_WDOG_BITE);
Kyle Yane45fa022016-08-29 11:40:26 -07001022 log_failure_reason(d);
1023 subsystem_restart_dev(d->subsys);
1024 }
1025}
1026
1027static irqreturn_t subsys_generic_handler(int irq, void *dev_id)
1028{
1029 struct pil_tz_data *d = subsys_to_data(dev_id);
Puja Gupta557f5292016-11-28 14:01:03 -08001030 uint32_t status_val, err_value;
Kyle Yane45fa022016-08-29 11:40:26 -07001031
Puja Gupta557f5292016-11-28 14:01:03 -08001032 err_value = __raw_readl(d->err_status_spare);
Kyle Yane45fa022016-08-29 11:40:26 -07001033 status_val = __raw_readl(d->irq_status);
1034
Puja Gupta557f5292016-11-28 14:01:03 -08001035 if ((status_val & BIT(d->bits_arr[ERR_READY])) && !err_value)
1036 clear_err_ready(d);
1037
1038 if ((status_val & BIT(d->bits_arr[ERR_READY])) &&
1039 err_value == 0x44554d50)
1040 clear_wdog(d);
1041
1042 if (status_val & BIT(d->bits_arr[PBL_DONE]))
1043 clear_pbl_done(d);
1044
Kyle Yane45fa022016-08-29 11:40:26 -07001045 return IRQ_HANDLED;
1046}
1047
1048static void mask_scsr_irqs(struct pil_tz_data *d)
1049{
1050 uint32_t mask_val;
1051 /* Masking all interrupts not handled by HLOS */
1052 mask_val = ~0;
1053 __raw_writel(mask_val & ~BIT(d->bits_arr[ERR_READY]) &
1054 ~BIT(d->bits_arr[PBL_DONE]), d->irq_mask);
1055}
1056
1057static int pil_tz_driver_probe(struct platform_device *pdev)
1058{
1059 struct pil_tz_data *d;
1060 struct resource *res;
1061 u32 proxy_timeout;
1062 int len, rc;
1063
1064 d = devm_kzalloc(&pdev->dev, sizeof(*d), GFP_KERNEL);
1065 if (!d)
1066 return -ENOMEM;
1067 platform_set_drvdata(pdev, d);
1068
1069 if (of_property_read_bool(pdev->dev.of_node, "qcom,pil-no-auth"))
1070 d->subsys_desc.no_auth = true;
1071
1072 d->keep_proxy_regs_on = of_property_read_bool(pdev->dev.of_node,
1073 "qcom,keep-proxy-regs-on");
1074
Avaneesh Kumar Dwivedi94619d92017-10-05 17:58:38 +05301075 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base_reg");
1076 d->reg_base = devm_ioremap_resource(&pdev->dev, res);
1077 if (IS_ERR(d->reg_base)) {
1078 dev_err(&pdev->dev, "Failed to ioremap base register\n");
1079 d->reg_base = NULL;
1080 }
1081
Kyle Yane45fa022016-08-29 11:40:26 -07001082 rc = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
1083 &d->desc.name);
1084 if (rc)
1085 return rc;
1086
1087 /* Defaulting smem_id to be not present */
1088 d->smem_id = -1;
1089
1090 if (of_find_property(pdev->dev.of_node, "qcom,smem-id", &len)) {
1091 rc = of_property_read_u32(pdev->dev.of_node, "qcom,smem-id",
1092 &d->smem_id);
1093 if (rc) {
1094 dev_err(&pdev->dev, "Failed to get the smem_id(rc:%d)\n",
1095 rc);
1096 return rc;
1097 }
1098 }
1099
1100 d->desc.dev = &pdev->dev;
1101 d->desc.owner = THIS_MODULE;
1102 d->desc.ops = &pil_ops_trusted;
1103
1104 d->desc.proxy_timeout = PROXY_TIMEOUT_MS;
Avaneesh Kumar Dwivedi7b506d22017-03-17 16:41:13 +05301105 d->desc.clear_fw_region = true;
Kyle Yane45fa022016-08-29 11:40:26 -07001106
1107 rc = of_property_read_u32(pdev->dev.of_node, "qcom,proxy-timeout-ms",
1108 &proxy_timeout);
1109 if (!rc)
1110 d->desc.proxy_timeout = proxy_timeout;
1111
1112 if (!d->subsys_desc.no_auth) {
1113 rc = piltz_resc_init(pdev, d);
1114 if (rc)
Kyle Yan3d6600c2017-01-06 14:04:26 -08001115 return rc;
Kyle Yane45fa022016-08-29 11:40:26 -07001116
1117 rc = of_property_read_u32(pdev->dev.of_node, "qcom,pas-id",
1118 &d->pas_id);
1119 if (rc) {
1120 dev_err(&pdev->dev, "Failed to find the pas_id(rc:%d)\n",
1121 rc);
1122 return rc;
1123 }
Kyle Yan9f57f572017-03-28 10:31:54 -07001124 scm_pas_init(MSM_BUS_MASTER_CRYPTO_CORE_0);
Kyle Yane45fa022016-08-29 11:40:26 -07001125 }
1126
1127 rc = pil_desc_init(&d->desc);
1128 if (rc)
1129 return rc;
1130
1131 init_completion(&d->stop_ack);
1132
1133 d->subsys_desc.name = d->desc.name;
1134 d->subsys_desc.owner = THIS_MODULE;
1135 d->subsys_desc.dev = &pdev->dev;
1136 d->subsys_desc.shutdown = subsys_shutdown;
1137 d->subsys_desc.powerup = subsys_powerup;
1138 d->subsys_desc.ramdump = subsys_ramdump;
1139 d->subsys_desc.free_memory = subsys_free_memory;
1140 d->subsys_desc.crash_shutdown = subsys_crash_shutdown;
1141 if (of_property_read_bool(pdev->dev.of_node,
1142 "qcom,pil-generic-irq-handler")) {
1143 d->subsys_desc.generic_handler = subsys_generic_handler;
1144 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1145 "sp2soc_irq_status");
1146 d->irq_status = devm_ioremap_resource(&pdev->dev, res);
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301147 if (IS_ERR(d->irq_status)) {
1148 dev_err(&pdev->dev, "Invalid resource for sp2soc_irq_status\n");
1149 rc = PTR_ERR(d->irq_status);
1150 goto err_ramdump;
1151 }
1152
Kyle Yane45fa022016-08-29 11:40:26 -07001153 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1154 "sp2soc_irq_clr");
1155 d->irq_clear = devm_ioremap_resource(&pdev->dev, res);
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301156 if (IS_ERR(d->irq_clear)) {
1157 dev_err(&pdev->dev, "Invalid resource for sp2soc_irq_clr\n");
1158 rc = PTR_ERR(d->irq_clear);
1159 goto err_ramdump;
1160 }
1161
Kyle Yane45fa022016-08-29 11:40:26 -07001162 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1163 "sp2soc_irq_mask");
1164 d->irq_mask = devm_ioremap_resource(&pdev->dev, res);
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301165 if (IS_ERR(d->irq_mask)) {
1166 dev_err(&pdev->dev, "Invalid resource for sp2soc_irq_mask\n");
1167 rc = PTR_ERR(d->irq_mask);
1168 goto err_ramdump;
1169 }
1170
Kyle Yane45fa022016-08-29 11:40:26 -07001171 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1172 "rmb_err");
1173 d->err_status = devm_ioremap_resource(&pdev->dev, res);
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301174 if (IS_ERR(d->err_status)) {
1175 dev_err(&pdev->dev, "Invalid resource for rmb_err\n");
1176 rc = PTR_ERR(d->err_status);
1177 goto err_ramdump;
1178 }
1179
Kyle Yane45fa022016-08-29 11:40:26 -07001180 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1181 "rmb_err_spare2");
1182 d->err_status_spare = devm_ioremap_resource(&pdev->dev, res);
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301183 if (IS_ERR(d->err_status_spare)) {
1184 dev_err(&pdev->dev, "Invalid resource for rmb_err_spare2\n");
1185 rc = PTR_ERR(d->err_status_spare);
1186 goto err_ramdump;
1187 }
1188
Kyle Yane45fa022016-08-29 11:40:26 -07001189 rc = of_property_read_u32_array(pdev->dev.of_node,
1190 "qcom,spss-scsr-bits", d->bits_arr, sizeof(d->bits_arr)/
1191 sizeof(d->bits_arr[0]));
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301192 if (rc) {
Kyle Yane45fa022016-08-29 11:40:26 -07001193 dev_err(&pdev->dev, "Failed to read qcom,spss-scsr-bits");
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301194 goto err_ramdump;
1195 }
Kyle Yane45fa022016-08-29 11:40:26 -07001196 mask_scsr_irqs(d);
1197
1198 } else {
1199 d->subsys_desc.err_fatal_handler =
1200 subsys_err_fatal_intr_handler;
1201 d->subsys_desc.wdog_bite_handler = subsys_wdog_bite_irq_handler;
1202 d->subsys_desc.stop_ack_handler = subsys_stop_ack_intr_handler;
1203 }
Kyle Yan0ceeb642017-09-13 11:21:35 -07001204 d->desc.signal_aop = of_property_read_bool(pdev->dev.of_node,
1205 "qcom,signal-aop");
1206 if (d->desc.signal_aop) {
1207 d->desc.cl.dev = &pdev->dev;
1208 d->desc.cl.tx_block = true;
1209 d->desc.cl.tx_tout = 1000;
1210 d->desc.cl.knows_txdone = false;
1211 d->desc.mbox = mbox_request_channel(&d->desc.cl, 0);
1212 if (IS_ERR(d->desc.mbox)) {
1213 rc = PTR_ERR(d->desc.mbox);
1214 dev_err(&pdev->dev, "Failed to get mailbox channel %pK %d\n",
1215 d->desc.mbox, rc);
1216 goto err_ramdump;
1217 }
1218 }
1219
Kyle Yane45fa022016-08-29 11:40:26 -07001220 d->ramdump_dev = create_ramdump_device(d->subsys_desc.name,
1221 &pdev->dev);
1222 if (!d->ramdump_dev) {
1223 rc = -ENOMEM;
1224 goto err_ramdump;
1225 }
1226
1227 d->subsys = subsys_register(&d->subsys_desc);
1228 if (IS_ERR(d->subsys)) {
1229 rc = PTR_ERR(d->subsys);
1230 goto err_subsys;
1231 }
1232
1233 return 0;
1234err_subsys:
1235 destroy_ramdump_device(d->ramdump_dev);
1236err_ramdump:
1237 pil_desc_release(&d->desc);
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301238 platform_set_drvdata(pdev, NULL);
Kyle Yane45fa022016-08-29 11:40:26 -07001239
1240 return rc;
1241}
1242
1243static int pil_tz_driver_exit(struct platform_device *pdev)
1244{
1245 struct pil_tz_data *d = platform_get_drvdata(pdev);
1246
1247 subsys_unregister(d->subsys);
1248 destroy_ramdump_device(d->ramdump_dev);
1249 pil_desc_release(&d->desc);
1250
1251 return 0;
1252}
1253
1254static const struct of_device_id pil_tz_match_table[] = {
1255 {.compatible = "qcom,pil-tz-generic"},
1256 {}
1257};
1258
1259static struct platform_driver pil_tz_driver = {
1260 .probe = pil_tz_driver_probe,
1261 .remove = pil_tz_driver_exit,
1262 .driver = {
1263 .name = "subsys-pil-tz",
1264 .of_match_table = pil_tz_match_table,
1265 .owner = THIS_MODULE,
1266 },
1267};
1268
1269static int __init pil_tz_init(void)
1270{
1271 return platform_driver_register(&pil_tz_driver);
1272}
1273module_init(pil_tz_init);
1274
1275static void __exit pil_tz_exit(void)
1276{
1277 platform_driver_unregister(&pil_tz_driver);
1278}
1279module_exit(pil_tz_exit);
1280
1281MODULE_DESCRIPTION("Support for booting subsystems");
1282MODULE_LICENSE("GPL v2");