]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/remoteproc/qcom_q6v5_pil.c
remoteproc: qcom: Driver for the self-authenticating Hexagon v5
[karo-tx-linux.git] / drivers / remoteproc / qcom_q6v5_pil.c
1 /*
2  * Qualcomm Peripheral Image Loader
3  *
4  * Copyright (C) 2016 Linaro Ltd.
5  * Copyright (C) 2014 Sony Mobile Communications AB
6  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  */
17
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <linux/dma-mapping.h>
22 #include <linux/firmware.h>
23 #include <linux/remoteproc.h>
24 #include <linux/interrupt.h>
25 #include <linux/memblock.h>
26 #include <linux/gpio/consumer.h>
27 #include <linux/of.h>
28 #include <linux/elf.h>
29 #include <linux/of_address.h>
30 #include <linux/of_device.h>
31 #include <linux/io.h>
32 #include <linux/delay.h>
33 #include <linux/clk.h>
34 #include <linux/slab.h>
35 #include <linux/regulator/consumer.h>
36 #include <linux/soc/qcom/smem.h>
37 #include <linux/soc/qcom/smem_state.h>
38 #include <linux/reset.h>
39
40 #include "remoteproc_internal.h"
41 #include "qcom_mdt_loader.h"
42
43 #include <linux/qcom_scm.h>
44
45 #define MBA_FIRMWARE_NAME               "mba.b00"
46 #define MPSS_FIRMWARE_NAME              "modem.mdt"
47
48 #define MPSS_CRASH_REASON_SMEM          421
49
50 #define VDD_MSS_UV_MIN                  1000000
51 #define VDD_MSS_UV_MAX                  1150000
52 #define VDD_MSS_UA                      100000
53
54 /* AXI Halting Registers */
55 #define MSS_Q6_HALT_BASE                0x180
56 #define MSS_MODEM_HALT_BASE             0x200
57 #define MSS_NC_HALT_BASE                0x280
58
59 /* RMB Status Register Values */
60 #define RMB_PBL_SUCCESS                 0x1
61
62 #define RMB_MBA_XPU_UNLOCKED            0x1
63 #define RMB_MBA_XPU_UNLOCKED_SCRIBBLED  0x2
64 #define RMB_MBA_META_DATA_AUTH_SUCCESS  0x3
65 #define RMB_MBA_AUTH_COMPLETE           0x4
66
67 /* PBL/MBA interface registers */
68 #define RMB_MBA_IMAGE_REG               0x00
69 #define RMB_PBL_STATUS_REG              0x04
70 #define RMB_MBA_COMMAND_REG             0x08
71 #define RMB_MBA_STATUS_REG              0x0C
72 #define RMB_PMI_META_DATA_REG           0x10
73 #define RMB_PMI_CODE_START_REG          0x14
74 #define RMB_PMI_CODE_LENGTH_REG         0x18
75
76 #define RMB_CMD_META_DATA_READY         0x1
77 #define RMB_CMD_LOAD_READY              0x2
78
79 /* QDSP6SS Register Offsets */
80 #define QDSP6SS_RESET_REG               0x014
81 #define QDSP6SS_GFMUX_CTL_REG           0x020
82 #define QDSP6SS_PWR_CTL_REG             0x030
83
84 /* AXI Halt Register Offsets */
85 #define AXI_HALTREQ_REG                 0x0
86 #define AXI_HALTACK_REG                 0x4
87 #define AXI_IDLE_REG                    0x8
88
89 #define HALT_ACK_TIMEOUT_MS             100
90
91 /* QDSP6SS_RESET */
92 #define Q6SS_STOP_CORE                  BIT(0)
93 #define Q6SS_CORE_ARES                  BIT(1)
94 #define Q6SS_BUS_ARES_ENABLE            BIT(2)
95
96 /* QDSP6SS_GFMUX_CTL */
97 #define Q6SS_CLK_ENABLE                 BIT(1)
98
99 /* QDSP6SS_PWR_CTL */
100 #define Q6SS_L2DATA_SLP_NRET_N_0        BIT(0)
101 #define Q6SS_L2DATA_SLP_NRET_N_1        BIT(1)
102 #define Q6SS_L2DATA_SLP_NRET_N_2        BIT(2)
103 #define Q6SS_L2TAG_SLP_NRET_N           BIT(16)
104 #define Q6SS_ETB_SLP_NRET_N             BIT(17)
105 #define Q6SS_L2DATA_STBY_N              BIT(18)
106 #define Q6SS_SLP_RET_N                  BIT(19)
107 #define Q6SS_CLAMP_IO                   BIT(20)
108 #define QDSS_BHS_ON                     BIT(21)
109 #define QDSS_LDO_BYP                    BIT(22)
110
111 struct q6v5 {
112         struct device *dev;
113         struct rproc *rproc;
114
115         void __iomem *reg_base;
116         void __iomem *halt_base;
117         void __iomem *rmb_base;
118
119         struct reset_control *mss_restart;
120
121         struct qcom_smem_state *state;
122         unsigned stop_bit;
123
124         struct regulator *vdd;
125
126         struct clk *ahb_clk;
127         struct clk *axi_clk;
128         struct clk *rom_clk;
129
130         struct completion start_done;
131
132         phys_addr_t mba_phys;
133         void *mba_region;
134         size_t mba_size;
135
136         phys_addr_t mpss_phys;
137         void *mpss_region;
138         size_t mpss_size;
139 };
140
141 static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
142 {
143         struct q6v5 *qproc = rproc->priv;
144
145         memcpy(qproc->mba_region, fw->data, fw->size);
146
147         return 0;
148 }
149
150 static const struct rproc_fw_ops q6v5_fw_ops = {
151         .find_rsc_table = qcom_mdt_find_rsc_table,
152         .load = q6v5_load,
153 };
154
155 static int q6v5_rmb_pbl_wait(struct q6v5 *qproc, int ms)
156 {
157         unsigned long timeout;
158         s32 val;
159
160         timeout = jiffies + msecs_to_jiffies(ms);
161         for (;;) {
162                 val = readl(qproc->rmb_base + RMB_PBL_STATUS_REG);
163                 if (val)
164                         break;
165
166                 if (time_after(jiffies, timeout))
167                         return -ETIMEDOUT;
168
169                 msleep(1);
170         }
171
172         return val;
173 }
174
175 static int q6v5_rmb_mba_wait(struct q6v5 *qproc, u32 status, int ms)
176 {
177
178         unsigned long timeout;
179         s32 val;
180
181         timeout = jiffies + msecs_to_jiffies(ms);
182         for (;;) {
183                 val = readl(qproc->rmb_base + RMB_MBA_STATUS_REG);
184                 if (val < 0)
185                         break;
186
187                 if (!status && val)
188                         break;
189                 else if (status && val == status)
190                         break;
191
192                 if (time_after(jiffies, timeout))
193                         return -ETIMEDOUT;
194
195                 msleep(1);
196         }
197
198         return val;
199 }
200
201 static void q6v5proc_reset(struct q6v5 *qproc)
202 {
203         u32 val;
204
205         /* Assert resets, stop core */
206         val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
207         val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE);
208         writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
209
210         /* Enable power block headswitch, and wait for it to stabilize */
211         val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
212         val |= QDSS_BHS_ON | QDSS_LDO_BYP;
213         writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
214         mb();
215         udelay(1);
216
217         /*
218          * Turn on memories. L2 banks should be done individually
219          * to minimize inrush current.
220          */
221         val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
222         val |= Q6SS_SLP_RET_N | Q6SS_L2TAG_SLP_NRET_N |
223                 Q6SS_ETB_SLP_NRET_N | Q6SS_L2DATA_STBY_N;
224         writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
225         val |= Q6SS_L2DATA_SLP_NRET_N_2;
226         writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
227         val |= Q6SS_L2DATA_SLP_NRET_N_1;
228         writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
229         val |= Q6SS_L2DATA_SLP_NRET_N_0;
230         writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
231
232         /* Remove IO clamp */
233         val &= ~Q6SS_CLAMP_IO;
234         writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
235
236         /* Bring core out of reset */
237         val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
238         val &= ~Q6SS_CORE_ARES;
239         writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
240
241         /* Turn on core clock */
242         val = readl(qproc->reg_base + QDSP6SS_GFMUX_CTL_REG);
243         val |= Q6SS_CLK_ENABLE;
244         writel(val, qproc->reg_base + QDSP6SS_GFMUX_CTL_REG);
245
246         /* Start core execution */
247         val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
248         val &= ~Q6SS_STOP_CORE;
249         writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
250 }
251
252 static void q6v5proc_halt_axi_port(struct q6v5 *qproc, void __iomem *halt)
253 {
254         unsigned long timeout;
255         u32 val;
256
257         /* Check if we're already idle */
258         if (readl(halt + AXI_IDLE_REG))
259                 return;
260
261         /* Assert halt request */
262         writel(1, halt + AXI_HALTREQ_REG);
263
264         /* Wait for halt */
265         timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS);
266         for (;;) {
267                 val = readl(halt + AXI_HALTACK_REG);
268                 if (val || time_after(jiffies, timeout))
269                         break;
270
271                 msleep(1);
272         }
273
274         if (!readl(halt + AXI_IDLE_REG))
275                 dev_err(qproc->dev, "port %pa failed halt\n", &halt);
276
277         /* Clear halt request (port will remain halted until reset) */
278         writel(0, halt + AXI_HALTREQ_REG);
279 }
280
281 static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
282 {
283         int ret;
284
285         /* Use mpss memory as scratch buffer for the mdt validation */
286         memcpy(qproc->mpss_region, fw->data, fw->size);
287
288         writel(qproc->mpss_phys, qproc->rmb_base + RMB_PMI_META_DATA_REG);
289         writel(RMB_CMD_META_DATA_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
290
291         ret = q6v5_rmb_mba_wait(qproc, RMB_MBA_META_DATA_AUTH_SUCCESS, 1000);
292         if (ret == -ETIMEDOUT)
293                 dev_err(qproc->dev, "MBA header authentication timed out\n");
294         else if (ret < 0)
295                 dev_err(qproc->dev, "MBA returned error %d for MDT header\n", ret);
296
297         return ret < 0 ? ret : 0;
298 }
299
300 static int q6v5_mpss_validate(struct q6v5 *qproc, const struct firmware *fw)
301 {
302         const struct elf32_phdr *phdrs;
303         const struct elf32_phdr *phdr;
304         struct elf32_hdr *ehdr;
305         size_t size;
306         u32 val;
307         int i;
308
309         ehdr = (struct elf32_hdr *)fw->data;
310         phdrs = (struct elf32_phdr *)(ehdr + 1);
311         for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
312                 phdr = &phdrs[i];
313
314                 if (phdr->p_type != PT_LOAD)
315                         continue;
316
317                 if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
318                         continue;
319
320                 if (!phdr->p_memsz)
321                         continue;
322
323                 size = readl(qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
324                 if (!size) {
325                         writel(qproc->mpss_phys, qproc->rmb_base + RMB_PMI_CODE_START_REG);
326                         writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
327                 }
328
329                 size += phdr->p_memsz;
330                 writel(size, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
331         }
332
333         val = readl(qproc->rmb_base + RMB_MBA_STATUS_REG);
334         return val < 0 ? val : 0;
335 }
336
337 static int q6v5_mpss_load(struct q6v5 *qproc)
338 {
339         const struct firmware *fw;
340         phys_addr_t fw_addr;
341         size_t fw_size;
342         bool relocate;
343         int ret;
344
345         ret = request_firmware(&fw, MPSS_FIRMWARE_NAME, qproc->dev);
346         if (ret < 0) {
347                 dev_err(qproc->dev, "unable to load " MPSS_FIRMWARE_NAME "\n");
348                 return ret;
349         }
350
351         ret = qcom_mdt_parse(fw, &fw_addr, &fw_size, &relocate);
352         if (ret) {
353                 dev_err(qproc->dev, "failed to parse mdt header\n");
354                 return ret;
355         }
356
357         /* Initialize the RMB validator */
358         writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
359
360         ret = q6v5_mpss_init_image(qproc, fw);
361         if (ret)
362                 goto release_firmware;
363
364         ret = qcom_mdt_load(qproc->rproc, fw, MPSS_FIRMWARE_NAME, fw_addr, qproc->mpss_region, qproc->mpss_size);
365         if (ret)
366                 goto release_firmware;
367
368         ret = q6v5_mpss_validate(qproc, fw);
369         if (ret)
370                 goto release_firmware;
371
372         ret = q6v5_rmb_mba_wait(qproc, RMB_MBA_AUTH_COMPLETE, 10000);
373         if (ret == -ETIMEDOUT)
374                 dev_err(qproc->dev, "MBA authentication timed out\n");
375         else if (ret < 0)
376                 dev_err(qproc->dev, "MBA returned error %d\n", ret);
377
378 release_firmware:
379         release_firmware(fw);
380
381         return ret < 0 ? ret : 0;
382 }
383
384 static int q6v5_start(struct rproc *rproc)
385 {
386         struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
387         int ret;
388
389         ret = regulator_enable(qproc->vdd);
390         if (ret) {
391                 dev_err(qproc->dev, "failed to enable mss vdd\n");
392                 return ret;
393         }
394
395         ret = reset_control_deassert(qproc->mss_restart);
396         if (ret) {
397                 dev_err(qproc->dev, "failed to deassert mss restart\n");
398                 goto disable_vdd;
399         }
400
401         ret = clk_prepare_enable(qproc->ahb_clk);
402         if (ret)
403                 goto assert_reset;
404
405         ret = clk_prepare_enable(qproc->axi_clk);
406         if (ret)
407                 goto disable_ahb_clk;
408
409         ret = clk_prepare_enable(qproc->rom_clk);
410         if (ret)
411                 goto disable_axi_clk;
412
413         writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG);
414
415         q6v5proc_reset(qproc);
416
417         ret = q6v5_rmb_pbl_wait(qproc, 1000);
418         if (ret == -ETIMEDOUT) {
419                 dev_err(qproc->dev, "PBL boot timed out\n");
420                 goto halt_axi_ports;
421         } else if (ret != RMB_PBL_SUCCESS) {
422                 dev_err(qproc->dev, "PBL returned unexpected status %d\n", ret);
423                 ret = -EINVAL;
424                 goto halt_axi_ports;
425         }
426
427         ret = q6v5_rmb_mba_wait(qproc, 0, 5000);
428         if (ret == -ETIMEDOUT) {
429                 dev_err(qproc->dev, "MBA boot timed out\n");
430                 goto halt_axi_ports;
431         } else if (ret != RMB_MBA_XPU_UNLOCKED && ret != RMB_MBA_XPU_UNLOCKED_SCRIBBLED) {
432                 dev_err(qproc->dev, "MBA returned unexpected status %d\n", ret);
433                 ret = -EINVAL;
434                 goto halt_axi_ports;
435         }
436
437         dev_info(qproc->dev, "MBA booted, loading mpss\n");
438
439         ret = q6v5_mpss_load(qproc);
440         if (ret)
441                 goto halt_axi_ports;
442
443         ret = wait_for_completion_timeout(&qproc->start_done,
444                                           msecs_to_jiffies(5000));
445         if (ret == 0) {
446                 dev_err(qproc->dev, "start timed out\n");
447                 ret = -ETIMEDOUT;
448                 goto halt_axi_ports;
449         }
450
451         /* All done, release the handover resources */
452
453         return 0;
454
455 halt_axi_ports:
456         q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_Q6_HALT_BASE);
457         q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_MODEM_HALT_BASE);
458         q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_NC_HALT_BASE);
459 disable_axi_clk:
460         clk_disable_unprepare(qproc->axi_clk);
461 disable_ahb_clk:
462         clk_disable_unprepare(qproc->ahb_clk);
463 assert_reset:
464         reset_control_assert(qproc->mss_restart);
465 disable_vdd:
466         regulator_disable(qproc->vdd);
467
468         return ret;
469 }
470
471 static int q6v5_stop(struct rproc *rproc)
472 {
473         struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
474
475         q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_Q6_HALT_BASE);
476         q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_MODEM_HALT_BASE);
477         q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_NC_HALT_BASE);
478
479         reset_control_assert(qproc->mss_restart);
480         clk_disable_unprepare(qproc->axi_clk);
481         clk_disable_unprepare(qproc->ahb_clk);
482         regulator_disable(qproc->vdd);
483
484         return 0;
485 }
486
487 static const struct rproc_ops q6v5_ops = {
488         .start = q6v5_start,
489         .stop = q6v5_stop,
490 };
491
492 static irqreturn_t q6v5_wdog_interrupt(int irq, void *dev)
493 {
494         struct q6v5 *qproc = dev;
495         size_t len;
496         char *msg;
497
498         msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, MPSS_CRASH_REASON_SMEM, &len);
499         if (!IS_ERR(msg) && len > 0 && msg[0])
500                 dev_err(qproc->dev, "watchdog received: %s\n", msg);
501         else
502                 dev_err(qproc->dev, "watchdog without message\n");
503
504         rproc_report_crash(qproc->rproc, RPROC_WATCHDOG);
505
506         if (!IS_ERR(msg))
507                 msg[0] = '\0';
508
509         return IRQ_HANDLED;
510 }
511
512 static irqreturn_t q6v5_fatal_interrupt(int irq, void *dev)
513 {
514         struct q6v5 *qproc = dev;
515         size_t len;
516         char *msg;
517
518         msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, MPSS_CRASH_REASON_SMEM, &len);
519         if (!IS_ERR(msg) && len > 0 && msg[0])
520                 dev_err(qproc->dev, "fatal error received: %s\n", msg);
521         else
522                 dev_err(qproc->dev, "fatal error without message\n");
523
524         rproc_report_crash(qproc->rproc, RPROC_FATAL_ERROR);
525
526         if (!IS_ERR(msg))
527                 msg[0] = '\0';
528
529         return IRQ_HANDLED;
530 }
531
532 static irqreturn_t q6v5_handover_interrupt(int irq, void *dev)
533 {
534         struct q6v5 *qproc = dev;
535
536         complete(&qproc->start_done);
537         return IRQ_HANDLED;
538 }
539
540 static irqreturn_t q6v5_stop_ack_interrupt(int irq, void *dev)
541 {
542         return IRQ_HANDLED;
543 }
544
545 static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev)
546 {
547         struct resource *res;
548
549         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6_base");
550         qproc->reg_base = devm_ioremap_resource(&pdev->dev, res);
551         if (IS_ERR(qproc->reg_base)) {
552                 dev_err(qproc->dev, "failed to get qdsp6_base\n");
553                 return PTR_ERR(qproc->reg_base);
554         }
555
556         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_base");
557         qproc->halt_base = devm_ioremap_resource(&pdev->dev, res);
558         if (IS_ERR(qproc->halt_base)) {
559                 dev_err(qproc->dev, "failed to get halt_base\n");
560                 return PTR_ERR(qproc->halt_base);
561         }
562
563         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb_base");
564         qproc->rmb_base = devm_ioremap_resource(&pdev->dev, res);
565         if (IS_ERR(qproc->rmb_base)) {
566                 dev_err(qproc->dev, "failed to get rmb_base\n");
567                 return PTR_ERR(qproc->rmb_base);
568         }
569
570         return 0;
571 }
572
573 static int q6v5_init_clocks(struct q6v5 *qproc)
574 {
575         qproc->ahb_clk = devm_clk_get(qproc->dev, "iface");
576         if (IS_ERR(qproc->ahb_clk)) {
577                 dev_err(qproc->dev, "failed to get iface clock\n");
578                 return PTR_ERR(qproc->ahb_clk);
579         }
580
581         qproc->axi_clk = devm_clk_get(qproc->dev, "bus");
582         if (IS_ERR(qproc->axi_clk)) {
583                 dev_err(qproc->dev, "failed to get bus clock\n");
584                 return PTR_ERR(qproc->axi_clk);
585         }
586
587         qproc->rom_clk = devm_clk_get(qproc->dev, "mem");
588         if (IS_ERR(qproc->rom_clk)) {
589                 dev_err(qproc->dev, "failed to get mem clock\n");
590                 return PTR_ERR(qproc->rom_clk);
591         }
592
593         return 0;
594 }
595
596 static int q6v5_init_regulators(struct q6v5 *qproc)
597 {
598         qproc->vdd = devm_regulator_get(qproc->dev, "vdd");
599         if (IS_ERR(qproc->vdd)) {
600                 dev_err(qproc->dev, "failed to get vdd supply\n");
601                 return PTR_ERR(qproc->vdd);
602         }
603
604         regulator_set_voltage(qproc->vdd, VDD_MSS_UV_MIN, VDD_MSS_UV_MAX);
605         regulator_set_load(qproc->vdd, VDD_MSS_UA);
606
607         return 0;
608 }
609
610 static int q6v5_init_reset(struct q6v5 *qproc)
611 {
612         qproc->mss_restart = devm_reset_control_get(qproc->dev, NULL);
613         if (IS_ERR(qproc->mss_restart)) {
614                 dev_err(qproc->dev, "failed to acquire mss restart\n");
615                 return PTR_ERR(qproc->mss_restart);
616         }
617
618         return 0;
619 }
620
621 static int q6v5_request_irq(struct q6v5 *qproc,
622                              struct platform_device *pdev,
623                              const char *name,
624                              irq_handler_t thread_fn)
625 {
626         int ret;
627
628         ret = platform_get_irq_byname(pdev, name);
629         if (ret < 0) {
630                 dev_err(&pdev->dev, "no %s IRQ defined\n", name);
631                 return ret;
632         }
633
634         ret = devm_request_threaded_irq(&pdev->dev, ret,
635                                         NULL, thread_fn,
636                                         IRQF_TRIGGER_RISING | IRQF_ONESHOT,
637                                         "q6v5", qproc);
638         if (ret)
639                 dev_err(&pdev->dev, "request %s IRQ failed\n", name);
640         return ret;
641 }
642
643 static int q6v5_alloc_memory_region(struct q6v5 *qproc)
644 {
645         struct device_node *child;
646         struct device_node *node;
647         struct resource r;
648         int ret;
649
650         child = of_get_child_by_name(qproc->dev->of_node, "mba");
651         node = of_parse_phandle(child, "memory-region", 0);
652         ret = of_address_to_resource(node, 0, &r);
653         if (ret) {
654                 dev_err(qproc->dev, "unable to resolve mba region\n");
655                 return ret;
656         }
657
658         qproc->mba_phys = r.start;
659         qproc->mba_size = resource_size(&r);
660         qproc->mba_region = devm_ioremap_wc(qproc->dev, qproc->mba_phys, qproc->mba_size);
661         if (!qproc->mba_region) {
662                 dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n",
663                         &r.start, qproc->mba_size);
664                 return -EBUSY;
665         }
666
667         child = of_get_child_by_name(qproc->dev->of_node, "mpss");
668         node = of_parse_phandle(child, "memory-region", 0);
669         ret = of_address_to_resource(node, 0, &r);
670         if (ret) {
671                 dev_err(qproc->dev, "unable to resolve mpss region\n");
672                 return ret;
673         }
674
675         qproc->mpss_phys = r.start;
676         qproc->mpss_size = resource_size(&r);
677         qproc->mpss_region = devm_ioremap_wc(qproc->dev, qproc->mpss_phys, qproc->mpss_size);
678         if (!qproc->mpss_region) {
679                 dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n",
680                         &r.start, qproc->mpss_size);
681                 return -EBUSY;
682         }
683
684         return 0;
685 }
686
687 static int q6v5_probe(struct platform_device *pdev)
688 {
689         struct q6v5 *qproc;
690         struct rproc *rproc;
691         int ret;
692
693         rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_ops,
694                             MBA_FIRMWARE_NAME, sizeof(*qproc));
695         if (!rproc) {
696                 dev_err(&pdev->dev, "failed to allocate rproc\n");
697                 return -ENOMEM;
698         }
699
700         rproc->fw_ops = &q6v5_fw_ops;
701
702         qproc = (struct q6v5 *)rproc->priv;
703         qproc->dev = &pdev->dev;
704         qproc->rproc = rproc;
705         platform_set_drvdata(pdev, qproc);
706
707         init_completion(&qproc->start_done);
708
709         ret = q6v5_init_mem(qproc, pdev);
710         if (ret)
711                 goto free_rproc;
712
713         ret = q6v5_alloc_memory_region(qproc);
714         if (ret)
715                 goto free_rproc;
716
717         ret = q6v5_init_clocks(qproc);
718         if (ret)
719                 goto free_rproc;
720
721         ret = q6v5_init_regulators(qproc);
722         if (ret)
723                 goto free_rproc;
724
725         ret = q6v5_init_reset(qproc);
726         if (ret)
727                 goto free_rproc;
728
729         ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt);
730         if (ret < 0)
731                 goto free_rproc;
732
733         ret = q6v5_request_irq(qproc, pdev, "fatal", q6v5_fatal_interrupt);
734         if (ret < 0)
735                 goto free_rproc;
736
737         ret = q6v5_request_irq(qproc, pdev, "handover", q6v5_handover_interrupt);
738         if (ret < 0)
739                 goto free_rproc;
740
741         ret = q6v5_request_irq(qproc, pdev, "stop-ack", q6v5_stop_ack_interrupt);
742         if (ret < 0)
743                 goto free_rproc;
744
745         qproc->state = qcom_smem_state_get(&pdev->dev, "stop", &qproc->stop_bit);
746         if (IS_ERR(qproc->state))
747                 goto free_rproc;
748
749         ret = rproc_add(rproc);
750         if (ret)
751                 goto free_rproc;
752
753         return 0;
754
755 free_rproc:
756         rproc_put(rproc);
757
758         return ret;
759 }
760
761 static int q6v5_remove(struct platform_device *pdev)
762 {
763         struct q6v5 *qproc = platform_get_drvdata(pdev);
764
765         rproc_del(qproc->rproc);
766         rproc_put(qproc->rproc);
767
768         return 0;
769 }
770
771 static const struct of_device_id q6v5_of_match[] = {
772         { .compatible = "qcom,q6v5-pil", },
773         { },
774 };
775
776 static struct platform_driver q6v5_driver = {
777         .probe = q6v5_probe,
778         .remove = q6v5_remove,
779         .driver = {
780                 .name = "qcom-q6v5-pil",
781                 .of_match_table = q6v5_of_match,
782         },
783 };
784
785 module_platform_driver(q6v5_driver);