blob: 5b600f6ce742fe8e9f825fde43a4d83b62f367b7 [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);
860
861 smem_reason[0] = '\0';
862 wmb();
863}
864
865static int subsys_shutdown(const struct subsys_desc *subsys, bool force_stop)
866{
867 struct pil_tz_data *d = subsys_to_data(subsys);
868 int ret;
869
870 if (!subsys_get_crash_status(d->subsys) && force_stop &&
871 subsys->force_stop_gpio) {
872 gpio_set_value(subsys->force_stop_gpio, 1);
873 ret = wait_for_completion_timeout(&d->stop_ack,
874 msecs_to_jiffies(STOP_ACK_TIMEOUT_MS));
875 if (!ret)
876 pr_warn("Timed out on stop ack from %s.\n",
877 subsys->name);
878 gpio_set_value(subsys->force_stop_gpio, 0);
879 }
880
881 pil_shutdown(&d->desc);
882 return 0;
883}
884
885static int subsys_powerup(const struct subsys_desc *subsys)
886{
887 struct pil_tz_data *d = subsys_to_data(subsys);
888 int ret = 0;
889
890 if (subsys->stop_ack_irq)
891 reinit_completion(&d->stop_ack);
892
893 d->desc.fw_name = subsys->fw_name;
894 ret = pil_boot(&d->desc);
895
896 return ret;
897}
898
899static int subsys_ramdump(int enable, const struct subsys_desc *subsys)
900{
901 struct pil_tz_data *d = subsys_to_data(subsys);
902
903 if (!enable)
904 return 0;
905
906 return pil_do_ramdump(&d->desc, d->ramdump_dev);
907}
908
909static void subsys_free_memory(const struct subsys_desc *subsys)
910{
911 struct pil_tz_data *d = subsys_to_data(subsys);
912
913 pil_free_memory(&d->desc);
914}
915
916static void subsys_crash_shutdown(const struct subsys_desc *subsys)
917{
918 struct pil_tz_data *d = subsys_to_data(subsys);
919
920 if (subsys->force_stop_gpio > 0 &&
921 !subsys_get_crash_status(d->subsys)) {
922 gpio_set_value(subsys->force_stop_gpio, 1);
923 mdelay(CRASH_STOP_ACK_TO_MS);
924 }
925}
926
927static irqreturn_t subsys_err_fatal_intr_handler (int irq, void *dev_id)
928{
929 struct pil_tz_data *d = subsys_to_data(dev_id);
Avaneesh Kumar Dwivedi94619d92017-10-05 17:58:38 +0530930 u32 nmi_status = 0;
Kyle Yane45fa022016-08-29 11:40:26 -0700931
Avaneesh Kumar Dwivedi94619d92017-10-05 17:58:38 +0530932 if (d->reg_base)
933 nmi_status = readl_relaxed(d->reg_base +
934 QDSP6SS_NMI_STATUS);
935
936 if (nmi_status & 0x04)
937 pr_err("%s: Fatal error on the %s due to TZ NMI\n",
938 __func__, d->subsys_desc.name);
939 else
940 pr_err("%s Fatal error on the %s\n",
941 __func__, d->subsys_desc.name);
942
Kyle Yane45fa022016-08-29 11:40:26 -0700943 if (subsys_get_crash_status(d->subsys)) {
944 pr_err("%s: Ignoring error fatal, restart in progress\n",
945 d->subsys_desc.name);
946 return IRQ_HANDLED;
947 }
Satya Durga Srinivasu Prabhala30af7d02016-12-15 13:33:39 -0800948 subsys_set_crash_status(d->subsys, CRASH_STATUS_ERR_FATAL);
Kyle Yane45fa022016-08-29 11:40:26 -0700949 log_failure_reason(d);
950 subsystem_restart_dev(d->subsys);
951
952 return IRQ_HANDLED;
953}
954
955static irqreturn_t subsys_wdog_bite_irq_handler(int irq, void *dev_id)
956{
957 struct pil_tz_data *d = subsys_to_data(dev_id);
958
959 if (subsys_get_crash_status(d->subsys))
960 return IRQ_HANDLED;
961 pr_err("Watchdog bite received from %s!\n", d->subsys_desc.name);
962
963 if (d->subsys_desc.system_debug &&
964 !gpio_get_value(d->subsys_desc.err_fatal_gpio))
965 panic("%s: System ramdump requested. Triggering device restart!\n",
966 __func__);
Satya Durga Srinivasu Prabhala30af7d02016-12-15 13:33:39 -0800967 subsys_set_crash_status(d->subsys, CRASH_STATUS_WDOG_BITE);
Kyle Yane45fa022016-08-29 11:40:26 -0700968 log_failure_reason(d);
969 subsystem_restart_dev(d->subsys);
970
971 return IRQ_HANDLED;
972}
973
974static irqreturn_t subsys_stop_ack_intr_handler(int irq, void *dev_id)
975{
976 struct pil_tz_data *d = subsys_to_data(dev_id);
977
978 pr_info("Received stop ack interrupt from %s\n", d->subsys_desc.name);
979 complete(&d->stop_ack);
980 return IRQ_HANDLED;
981}
982
Puja Gupta557f5292016-11-28 14:01:03 -0800983static void clear_pbl_done(struct pil_tz_data *d)
Kyle Yane45fa022016-08-29 11:40:26 -0700984{
985 uint32_t err_value;
986
987 err_value = __raw_readl(d->err_status);
988 pr_debug("PBL_DONE received from %s!\n", d->subsys_desc.name);
989 if (err_value) {
990 uint32_t rmb_err_spare0;
991 uint32_t rmb_err_spare1;
992 uint32_t rmb_err_spare2;
993
994 rmb_err_spare2 = __raw_readl(d->err_status_spare);
995 rmb_err_spare1 = __raw_readl(d->err_status_spare-4);
996 rmb_err_spare0 = __raw_readl(d->err_status_spare-8);
997
998 pr_err("PBL error status register: 0x%08x\n", err_value);
999
1000 pr_err("PBL error status spare0 register: 0x%08x\n",
1001 rmb_err_spare0);
1002 pr_err("PBL error status spare1 register: 0x%08x\n",
1003 rmb_err_spare1);
1004 pr_err("PBL error status spare2 register: 0x%08x\n",
1005 rmb_err_spare2);
1006 }
1007 __raw_writel(BIT(d->bits_arr[PBL_DONE]), d->irq_clear);
1008}
1009
Puja Gupta557f5292016-11-28 14:01:03 -08001010static void clear_err_ready(struct pil_tz_data *d)
Kyle Yane45fa022016-08-29 11:40:26 -07001011{
Puja Gupta557f5292016-11-28 14:01:03 -08001012 pr_debug("Subsystem error services up received from %s\n",
Kyle Yane45fa022016-08-29 11:40:26 -07001013 d->subsys_desc.name);
Puja Gupta557f5292016-11-28 14:01:03 -08001014 __raw_writel(BIT(d->bits_arr[ERR_READY]), d->irq_clear);
1015 complete_err_ready(d->subsys);
1016}
1017
1018static void clear_wdog(struct pil_tz_data *d)
1019{
1020 /* Check crash status to know if device is restarting*/
1021 if (!subsys_get_crash_status(d->subsys)) {
Kyle Yane45fa022016-08-29 11:40:26 -07001022 pr_err("wdog bite received from %s!\n", d->subsys_desc.name);
1023 __raw_writel(BIT(d->bits_arr[ERR_READY]), d->irq_clear);
Satya Durga Srinivasu Prabhala30af7d02016-12-15 13:33:39 -08001024 subsys_set_crash_status(d->subsys, CRASH_STATUS_WDOG_BITE);
Kyle Yane45fa022016-08-29 11:40:26 -07001025 log_failure_reason(d);
1026 subsystem_restart_dev(d->subsys);
1027 }
1028}
1029
1030static irqreturn_t subsys_generic_handler(int irq, void *dev_id)
1031{
1032 struct pil_tz_data *d = subsys_to_data(dev_id);
Puja Gupta557f5292016-11-28 14:01:03 -08001033 uint32_t status_val, err_value;
Kyle Yane45fa022016-08-29 11:40:26 -07001034
Puja Gupta557f5292016-11-28 14:01:03 -08001035 err_value = __raw_readl(d->err_status_spare);
Kyle Yane45fa022016-08-29 11:40:26 -07001036 status_val = __raw_readl(d->irq_status);
1037
Puja Gupta557f5292016-11-28 14:01:03 -08001038 if ((status_val & BIT(d->bits_arr[ERR_READY])) && !err_value)
1039 clear_err_ready(d);
1040
1041 if ((status_val & BIT(d->bits_arr[ERR_READY])) &&
1042 err_value == 0x44554d50)
1043 clear_wdog(d);
1044
1045 if (status_val & BIT(d->bits_arr[PBL_DONE]))
1046 clear_pbl_done(d);
1047
Kyle Yane45fa022016-08-29 11:40:26 -07001048 return IRQ_HANDLED;
1049}
1050
1051static void mask_scsr_irqs(struct pil_tz_data *d)
1052{
1053 uint32_t mask_val;
1054 /* Masking all interrupts not handled by HLOS */
1055 mask_val = ~0;
1056 __raw_writel(mask_val & ~BIT(d->bits_arr[ERR_READY]) &
1057 ~BIT(d->bits_arr[PBL_DONE]), d->irq_mask);
1058}
1059
1060static int pil_tz_driver_probe(struct platform_device *pdev)
1061{
1062 struct pil_tz_data *d;
1063 struct resource *res;
1064 u32 proxy_timeout;
1065 int len, rc;
1066
1067 d = devm_kzalloc(&pdev->dev, sizeof(*d), GFP_KERNEL);
1068 if (!d)
1069 return -ENOMEM;
1070 platform_set_drvdata(pdev, d);
1071
1072 if (of_property_read_bool(pdev->dev.of_node, "qcom,pil-no-auth"))
1073 d->subsys_desc.no_auth = true;
1074
1075 d->keep_proxy_regs_on = of_property_read_bool(pdev->dev.of_node,
1076 "qcom,keep-proxy-regs-on");
1077
Avaneesh Kumar Dwivedi94619d92017-10-05 17:58:38 +05301078 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base_reg");
1079 d->reg_base = devm_ioremap_resource(&pdev->dev, res);
1080 if (IS_ERR(d->reg_base)) {
1081 dev_err(&pdev->dev, "Failed to ioremap base register\n");
1082 d->reg_base = NULL;
1083 }
1084
Kyle Yane45fa022016-08-29 11:40:26 -07001085 rc = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
1086 &d->desc.name);
1087 if (rc)
1088 return rc;
1089
1090 /* Defaulting smem_id to be not present */
1091 d->smem_id = -1;
1092
1093 if (of_find_property(pdev->dev.of_node, "qcom,smem-id", &len)) {
1094 rc = of_property_read_u32(pdev->dev.of_node, "qcom,smem-id",
1095 &d->smem_id);
1096 if (rc) {
1097 dev_err(&pdev->dev, "Failed to get the smem_id(rc:%d)\n",
1098 rc);
1099 return rc;
1100 }
1101 }
1102
1103 d->desc.dev = &pdev->dev;
1104 d->desc.owner = THIS_MODULE;
1105 d->desc.ops = &pil_ops_trusted;
1106
1107 d->desc.proxy_timeout = PROXY_TIMEOUT_MS;
Avaneesh Kumar Dwivedi7b506d22017-03-17 16:41:13 +05301108 d->desc.clear_fw_region = true;
Kyle Yane45fa022016-08-29 11:40:26 -07001109
1110 rc = of_property_read_u32(pdev->dev.of_node, "qcom,proxy-timeout-ms",
1111 &proxy_timeout);
1112 if (!rc)
1113 d->desc.proxy_timeout = proxy_timeout;
1114
1115 if (!d->subsys_desc.no_auth) {
1116 rc = piltz_resc_init(pdev, d);
1117 if (rc)
Kyle Yan3d6600c2017-01-06 14:04:26 -08001118 return rc;
Kyle Yane45fa022016-08-29 11:40:26 -07001119
1120 rc = of_property_read_u32(pdev->dev.of_node, "qcom,pas-id",
1121 &d->pas_id);
1122 if (rc) {
1123 dev_err(&pdev->dev, "Failed to find the pas_id(rc:%d)\n",
1124 rc);
1125 return rc;
1126 }
Kyle Yan9f57f572017-03-28 10:31:54 -07001127 scm_pas_init(MSM_BUS_MASTER_CRYPTO_CORE_0);
Kyle Yane45fa022016-08-29 11:40:26 -07001128 }
1129
1130 rc = pil_desc_init(&d->desc);
1131 if (rc)
1132 return rc;
1133
1134 init_completion(&d->stop_ack);
1135
1136 d->subsys_desc.name = d->desc.name;
1137 d->subsys_desc.owner = THIS_MODULE;
1138 d->subsys_desc.dev = &pdev->dev;
1139 d->subsys_desc.shutdown = subsys_shutdown;
1140 d->subsys_desc.powerup = subsys_powerup;
1141 d->subsys_desc.ramdump = subsys_ramdump;
1142 d->subsys_desc.free_memory = subsys_free_memory;
1143 d->subsys_desc.crash_shutdown = subsys_crash_shutdown;
1144 if (of_property_read_bool(pdev->dev.of_node,
1145 "qcom,pil-generic-irq-handler")) {
1146 d->subsys_desc.generic_handler = subsys_generic_handler;
1147 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1148 "sp2soc_irq_status");
1149 d->irq_status = devm_ioremap_resource(&pdev->dev, res);
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301150 if (IS_ERR(d->irq_status)) {
1151 dev_err(&pdev->dev, "Invalid resource for sp2soc_irq_status\n");
1152 rc = PTR_ERR(d->irq_status);
1153 goto err_ramdump;
1154 }
1155
Kyle Yane45fa022016-08-29 11:40:26 -07001156 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1157 "sp2soc_irq_clr");
1158 d->irq_clear = devm_ioremap_resource(&pdev->dev, res);
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301159 if (IS_ERR(d->irq_clear)) {
1160 dev_err(&pdev->dev, "Invalid resource for sp2soc_irq_clr\n");
1161 rc = PTR_ERR(d->irq_clear);
1162 goto err_ramdump;
1163 }
1164
Kyle Yane45fa022016-08-29 11:40:26 -07001165 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1166 "sp2soc_irq_mask");
1167 d->irq_mask = devm_ioremap_resource(&pdev->dev, res);
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301168 if (IS_ERR(d->irq_mask)) {
1169 dev_err(&pdev->dev, "Invalid resource for sp2soc_irq_mask\n");
1170 rc = PTR_ERR(d->irq_mask);
1171 goto err_ramdump;
1172 }
1173
Kyle Yane45fa022016-08-29 11:40:26 -07001174 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1175 "rmb_err");
1176 d->err_status = devm_ioremap_resource(&pdev->dev, res);
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301177 if (IS_ERR(d->err_status)) {
1178 dev_err(&pdev->dev, "Invalid resource for rmb_err\n");
1179 rc = PTR_ERR(d->err_status);
1180 goto err_ramdump;
1181 }
1182
Kyle Yane45fa022016-08-29 11:40:26 -07001183 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1184 "rmb_err_spare2");
1185 d->err_status_spare = devm_ioremap_resource(&pdev->dev, res);
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301186 if (IS_ERR(d->err_status_spare)) {
1187 dev_err(&pdev->dev, "Invalid resource for rmb_err_spare2\n");
1188 rc = PTR_ERR(d->err_status_spare);
1189 goto err_ramdump;
1190 }
1191
Kyle Yane45fa022016-08-29 11:40:26 -07001192 rc = of_property_read_u32_array(pdev->dev.of_node,
1193 "qcom,spss-scsr-bits", d->bits_arr, sizeof(d->bits_arr)/
1194 sizeof(d->bits_arr[0]));
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301195 if (rc) {
Kyle Yane45fa022016-08-29 11:40:26 -07001196 dev_err(&pdev->dev, "Failed to read qcom,spss-scsr-bits");
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301197 goto err_ramdump;
1198 }
Kyle Yane45fa022016-08-29 11:40:26 -07001199 mask_scsr_irqs(d);
1200
1201 } else {
1202 d->subsys_desc.err_fatal_handler =
1203 subsys_err_fatal_intr_handler;
1204 d->subsys_desc.wdog_bite_handler = subsys_wdog_bite_irq_handler;
1205 d->subsys_desc.stop_ack_handler = subsys_stop_ack_intr_handler;
1206 }
Kyle Yan0ceeb642017-09-13 11:21:35 -07001207 d->desc.signal_aop = of_property_read_bool(pdev->dev.of_node,
1208 "qcom,signal-aop");
1209 if (d->desc.signal_aop) {
1210 d->desc.cl.dev = &pdev->dev;
1211 d->desc.cl.tx_block = true;
1212 d->desc.cl.tx_tout = 1000;
1213 d->desc.cl.knows_txdone = false;
1214 d->desc.mbox = mbox_request_channel(&d->desc.cl, 0);
1215 if (IS_ERR(d->desc.mbox)) {
1216 rc = PTR_ERR(d->desc.mbox);
1217 dev_err(&pdev->dev, "Failed to get mailbox channel %pK %d\n",
1218 d->desc.mbox, rc);
1219 goto err_ramdump;
1220 }
1221 }
1222
Kyle Yane45fa022016-08-29 11:40:26 -07001223 d->ramdump_dev = create_ramdump_device(d->subsys_desc.name,
1224 &pdev->dev);
1225 if (!d->ramdump_dev) {
1226 rc = -ENOMEM;
1227 goto err_ramdump;
1228 }
1229
1230 d->subsys = subsys_register(&d->subsys_desc);
1231 if (IS_ERR(d->subsys)) {
1232 rc = PTR_ERR(d->subsys);
1233 goto err_subsys;
1234 }
1235
1236 return 0;
1237err_subsys:
1238 destroy_ramdump_device(d->ramdump_dev);
1239err_ramdump:
1240 pil_desc_release(&d->desc);
Jitendra Sharma76e0c842017-10-25 16:16:36 +05301241 platform_set_drvdata(pdev, NULL);
Kyle Yane45fa022016-08-29 11:40:26 -07001242
1243 return rc;
1244}
1245
1246static int pil_tz_driver_exit(struct platform_device *pdev)
1247{
1248 struct pil_tz_data *d = platform_get_drvdata(pdev);
1249
1250 subsys_unregister(d->subsys);
1251 destroy_ramdump_device(d->ramdump_dev);
1252 pil_desc_release(&d->desc);
1253
1254 return 0;
1255}
1256
1257static const struct of_device_id pil_tz_match_table[] = {
1258 {.compatible = "qcom,pil-tz-generic"},
1259 {}
1260};
1261
1262static struct platform_driver pil_tz_driver = {
1263 .probe = pil_tz_driver_probe,
1264 .remove = pil_tz_driver_exit,
1265 .driver = {
1266 .name = "subsys-pil-tz",
1267 .of_match_table = pil_tz_match_table,
1268 .owner = THIS_MODULE,
1269 },
1270};
1271
1272static int __init pil_tz_init(void)
1273{
1274 return platform_driver_register(&pil_tz_driver);
1275}
1276module_init(pil_tz_init);
1277
1278static void __exit pil_tz_exit(void)
1279{
1280 platform_driver_unregister(&pil_tz_driver);
1281}
1282module_exit(pil_tz_exit);
1283
1284MODULE_DESCRIPTION("Support for booting subsystems");
1285MODULE_LICENSE("GPL v2");