aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-08-18 19:42:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-18 19:42:04 -0400
commitc54fc8658b501b412d006886ebe3e8543a30a122 (patch)
treebeb6a843a1c838f0499d8417706296a8c97e0f0e
parent6eaac34ff30e189fda28110298ca9fbfb2f51e28 (diff)
parentb2201ee554a5811f569f31280b0079e7d6177606 (diff)
Merge tag 'rproc-v4.19' of git://github.com/andersson/remoteproc
Pull remoteproc updates from Bjorn Andersson: "This adds support for pre-start and post-shutdown hooks for remoteproc subdevices, refactors the Qualcomm Hexagon support to allow reuse between several drivers, makes authentication in the MDT file loader optional, migrates a few format strings to use %pK and migrates the Davinci driver to use the reset framework" * tag 'rproc-v4.19' of git://github.com/andersson/remoteproc: remoteproc/davinci: use the reset framework remoteproc/davinci: Mark error recovery as disabled remoteproc: st_slim: replace "%p" with "%pK" remoteproc: replace "%p" with "%pK" remoteproc: qcom: fix Q6V5_WCSS dependencies remoteproc: Reset table_ptr in rproc_start() failure paths remoteproc: qcom: q6v5-pil: fix modem hang on SDM845 after axis2 clk unvote remoteproc: qcom q6v5: fix modular build remoteproc: Introduce prepare and unprepare for subdevices remoteproc: rename subdev probe and remove functions remoteproc: Make client initialize ops in rproc_subdev remoteproc: Make start and stop in subdev optional remoteproc: Rename subdev functions to start/stop remoteproc: qcom: Introduce Hexagon V5 based WCSS driver remoteproc: qcom: q6v5-pil: Use common q6v5 helpers remoteproc: qcom: adsp: Use common q6v5 helpers remoteproc: q6v5: Extract common resource handling remoteproc: qcom: mdt_loader: Make the firmware authentication optional
-rw-r--r--Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt7
-rw-r--r--drivers/remoteproc/Kconfig23
-rw-r--r--drivers/remoteproc/Makefile2
-rw-r--r--drivers/remoteproc/da8xx_remoteproc.c37
-rw-r--r--drivers/remoteproc/qcom_adsp_pil.c156
-rw-r--r--drivers/remoteproc/qcom_common.c26
-rw-r--r--drivers/remoteproc/qcom_q6v5.c252
-rw-r--r--drivers/remoteproc/qcom_q6v5.h46
-rw-r--r--drivers/remoteproc/qcom_q6v5_pil.c158
-rw-r--r--drivers/remoteproc/qcom_q6v5_wcss.c601
-rw-r--r--drivers/remoteproc/qcom_sysmon.c5
-rw-r--r--drivers/remoteproc/remoteproc_core.c117
-rw-r--r--drivers/remoteproc/remoteproc_debugfs.c4
-rw-r--r--drivers/remoteproc/remoteproc_virtio.c2
-rw-r--r--drivers/remoteproc/st_slim_rproc.c3
-rw-r--r--drivers/soc/qcom/mdt_loader.c87
-rw-r--r--include/linux/remoteproc.h19
-rw-r--r--include/linux/soc/qcom/mdt_loader.h4
18 files changed, 1188 insertions, 361 deletions
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt
index d90182425450..601dd9f389aa 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt
@@ -8,6 +8,7 @@ on the Qualcomm Hexagon core.
8 Value type: <string> 8 Value type: <string>
9 Definition: must be one of: 9 Definition: must be one of:
10 "qcom,q6v5-pil", 10 "qcom,q6v5-pil",
11 "qcom,ipq8074-wcss-pil"
11 "qcom,msm8916-mss-pil", 12 "qcom,msm8916-mss-pil",
12 "qcom,msm8974-mss-pil" 13 "qcom,msm8974-mss-pil"
13 "qcom,msm8996-mss-pil" 14 "qcom,msm8996-mss-pil"
@@ -50,11 +51,15 @@ on the Qualcomm Hexagon core.
50 Usage: required 51 Usage: required
51 Value type: <phandle> 52 Value type: <phandle>
52 Definition: reference to the reset-controller for the modem sub-system 53 Definition: reference to the reset-controller for the modem sub-system
54 reference to the list of 3 reset-controllers for the
55 wcss sub-system
53 56
54- reset-names: 57- reset-names:
55 Usage: required 58 Usage: required
56 Value type: <stringlist> 59 Value type: <stringlist>
57 Definition: must be "mss_restart" 60 Definition: must be "mss_restart" for the modem sub-system
61 Definition: must be "wcss_aon_reset", "wcss_reset", "wcss_q6_reset"
62 for the wcss syb-system
58 63
59- cx-supply: 64- cx-supply:
60- mss-supply: 65- mss-supply:
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index cd1c168fd188..052d4dd347f9 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -93,6 +93,7 @@ config QCOM_ADSP_PIL
93 depends on QCOM_SYSMON || QCOM_SYSMON=n 93 depends on QCOM_SYSMON || QCOM_SYSMON=n
94 select MFD_SYSCON 94 select MFD_SYSCON
95 select QCOM_MDT_LOADER 95 select QCOM_MDT_LOADER
96 select QCOM_Q6V5_COMMON
96 select QCOM_RPROC_COMMON 97 select QCOM_RPROC_COMMON
97 select QCOM_SCM 98 select QCOM_SCM
98 help 99 help
@@ -102,6 +103,11 @@ config QCOM_ADSP_PIL
102config QCOM_RPROC_COMMON 103config QCOM_RPROC_COMMON
103 tristate 104 tristate
104 105
106config QCOM_Q6V5_COMMON
107 tristate
108 depends on ARCH_QCOM
109 depends on QCOM_SMEM
110
105config QCOM_Q6V5_PIL 111config QCOM_Q6V5_PIL
106 tristate "Qualcomm Hexagon V5 Peripherial Image Loader" 112 tristate "Qualcomm Hexagon V5 Peripherial Image Loader"
107 depends on OF && ARCH_QCOM 113 depends on OF && ARCH_QCOM
@@ -110,12 +116,29 @@ config QCOM_Q6V5_PIL
110 depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n 116 depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
111 depends on QCOM_SYSMON || QCOM_SYSMON=n 117 depends on QCOM_SYSMON || QCOM_SYSMON=n
112 select MFD_SYSCON 118 select MFD_SYSCON
119 select QCOM_Q6V5_COMMON
113 select QCOM_RPROC_COMMON 120 select QCOM_RPROC_COMMON
114 select QCOM_SCM 121 select QCOM_SCM
115 help 122 help
116 Say y here to support the Qualcomm Peripherial Image Loader for the 123 Say y here to support the Qualcomm Peripherial Image Loader for the
117 Hexagon V5 based remote processors. 124 Hexagon V5 based remote processors.
118 125
126config QCOM_Q6V5_WCSS
127 tristate "Qualcomm Hexagon based WCSS Peripheral Image Loader"
128 depends on OF && ARCH_QCOM
129 depends on QCOM_SMEM
130 depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n)
131 depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
132 depends on QCOM_SYSMON || QCOM_SYSMON=n
133 select MFD_SYSCON
134 select QCOM_MDT_LOADER
135 select QCOM_Q6V5_COMMON
136 select QCOM_RPROC_COMMON
137 select QCOM_SCM
138 help
139 Say y here to support the Qualcomm Peripheral Image Loader for the
140 Hexagon V5 based WCSS remote processors.
141
119config QCOM_SYSMON 142config QCOM_SYSMON
120 tristate "Qualcomm sysmon driver" 143 tristate "Qualcomm sysmon driver"
121 depends on RPMSG 144 depends on RPMSG
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 02627ede8d4a..03332fa7e2ee 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -16,7 +16,9 @@ obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
16obj-$(CONFIG_KEYSTONE_REMOTEPROC) += keystone_remoteproc.o 16obj-$(CONFIG_KEYSTONE_REMOTEPROC) += keystone_remoteproc.o
17obj-$(CONFIG_QCOM_ADSP_PIL) += qcom_adsp_pil.o 17obj-$(CONFIG_QCOM_ADSP_PIL) += qcom_adsp_pil.o
18obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o 18obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o
19obj-$(CONFIG_QCOM_Q6V5_COMMON) += qcom_q6v5.o
19obj-$(CONFIG_QCOM_Q6V5_PIL) += qcom_q6v5_pil.o 20obj-$(CONFIG_QCOM_Q6V5_PIL) += qcom_q6v5_pil.o
21obj-$(CONFIG_QCOM_Q6V5_WCSS) += qcom_q6v5_wcss.o
20obj-$(CONFIG_QCOM_SYSMON) += qcom_sysmon.o 22obj-$(CONFIG_QCOM_SYSMON) += qcom_sysmon.o
21obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss_pil.o 23obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss_pil.o
22qcom_wcnss_pil-y += qcom_wcnss.o 24qcom_wcnss_pil-y += qcom_wcnss.o
diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c
index b668e32996e2..e230bef71be1 100644
--- a/drivers/remoteproc/da8xx_remoteproc.c
+++ b/drivers/remoteproc/da8xx_remoteproc.c
@@ -10,6 +10,7 @@
10 10
11#include <linux/bitops.h> 11#include <linux/bitops.h>
12#include <linux/clk.h> 12#include <linux/clk.h>
13#include <linux/reset.h>
13#include <linux/err.h> 14#include <linux/err.h>
14#include <linux/interrupt.h> 15#include <linux/interrupt.h>
15#include <linux/io.h> 16#include <linux/io.h>
@@ -20,8 +21,6 @@
20#include <linux/platform_device.h> 21#include <linux/platform_device.h>
21#include <linux/remoteproc.h> 22#include <linux/remoteproc.h>
22 23
23#include <mach/clock.h> /* for davinci_clk_reset_assert/deassert() */
24
25#include "remoteproc_internal.h" 24#include "remoteproc_internal.h"
26 25
27static char *da8xx_fw_name; 26static char *da8xx_fw_name;
@@ -72,6 +71,7 @@ struct da8xx_rproc {
72 struct da8xx_rproc_mem *mem; 71 struct da8xx_rproc_mem *mem;
73 int num_mems; 72 int num_mems;
74 struct clk *dsp_clk; 73 struct clk *dsp_clk;
74 struct reset_control *dsp_reset;
75 void (*ack_fxn)(struct irq_data *data); 75 void (*ack_fxn)(struct irq_data *data);
76 struct irq_data *irq_data; 76 struct irq_data *irq_data;
77 void __iomem *chipsig; 77 void __iomem *chipsig;
@@ -138,6 +138,7 @@ static int da8xx_rproc_start(struct rproc *rproc)
138 struct device *dev = rproc->dev.parent; 138 struct device *dev = rproc->dev.parent;
139 struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; 139 struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
140 struct clk *dsp_clk = drproc->dsp_clk; 140 struct clk *dsp_clk = drproc->dsp_clk;
141 struct reset_control *dsp_reset = drproc->dsp_reset;
141 int ret; 142 int ret;
142 143
143 /* hw requires the start (boot) address be on 1KB boundary */ 144 /* hw requires the start (boot) address be on 1KB boundary */
@@ -155,7 +156,12 @@ static int da8xx_rproc_start(struct rproc *rproc)
155 return ret; 156 return ret;
156 } 157 }
157 158
158 davinci_clk_reset_deassert(dsp_clk); 159 ret = reset_control_deassert(dsp_reset);
160 if (ret) {
161 dev_err(dev, "reset_control_deassert() failed: %d\n", ret);
162 clk_disable_unprepare(dsp_clk);
163 return ret;
164 }
159 165
160 return 0; 166 return 0;
161} 167}
@@ -163,8 +169,15 @@ static int da8xx_rproc_start(struct rproc *rproc)
163static int da8xx_rproc_stop(struct rproc *rproc) 169static int da8xx_rproc_stop(struct rproc *rproc)
164{ 170{
165 struct da8xx_rproc *drproc = rproc->priv; 171 struct da8xx_rproc *drproc = rproc->priv;
172 struct device *dev = rproc->dev.parent;
173 int ret;
174
175 ret = reset_control_assert(drproc->dsp_reset);
176 if (ret) {
177 dev_err(dev, "reset_control_assert() failed: %d\n", ret);
178 return ret;
179 }
166 180
167 davinci_clk_reset_assert(drproc->dsp_clk);
168 clk_disable_unprepare(drproc->dsp_clk); 181 clk_disable_unprepare(drproc->dsp_clk);
169 182
170 return 0; 183 return 0;
@@ -232,6 +245,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
232 struct resource *bootreg_res; 245 struct resource *bootreg_res;
233 struct resource *chipsig_res; 246 struct resource *chipsig_res;
234 struct clk *dsp_clk; 247 struct clk *dsp_clk;
248 struct reset_control *dsp_reset;
235 void __iomem *chipsig; 249 void __iomem *chipsig;
236 void __iomem *bootreg; 250 void __iomem *bootreg;
237 int irq; 251 int irq;
@@ -268,6 +282,15 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
268 return PTR_ERR(dsp_clk); 282 return PTR_ERR(dsp_clk);
269 } 283 }
270 284
285 dsp_reset = devm_reset_control_get_exclusive(dev, NULL);
286 if (IS_ERR(dsp_reset)) {
287 if (PTR_ERR(dsp_reset) != -EPROBE_DEFER)
288 dev_err(dev, "unable to get reset control: %ld\n",
289 PTR_ERR(dsp_reset));
290
291 return PTR_ERR(dsp_reset);
292 }
293
271 if (dev->of_node) { 294 if (dev->of_node) {
272 ret = of_reserved_mem_device_init(dev); 295 ret = of_reserved_mem_device_init(dev);
273 if (ret) { 296 if (ret) {
@@ -284,9 +307,13 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
284 goto free_mem; 307 goto free_mem;
285 } 308 }
286 309
310 /* error recovery is not supported at present */
311 rproc->recovery_disabled = true;
312
287 drproc = rproc->priv; 313 drproc = rproc->priv;
288 drproc->rproc = rproc; 314 drproc->rproc = rproc;
289 drproc->dsp_clk = dsp_clk; 315 drproc->dsp_clk = dsp_clk;
316 drproc->dsp_reset = dsp_reset;
290 rproc->has_iommu = false; 317 rproc->has_iommu = false;
291 318
292 ret = da8xx_rproc_get_internal_memories(pdev, drproc); 319 ret = da8xx_rproc_get_internal_memories(pdev, drproc);
@@ -309,7 +336,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
309 * *not* in reset, but da8xx_rproc_start() needs the DSP to be 336 * *not* in reset, but da8xx_rproc_start() needs the DSP to be
310 * held in reset at the time it is called. 337 * held in reset at the time it is called.
311 */ 338 */
312 ret = davinci_clk_reset_assert(drproc->dsp_clk); 339 ret = reset_control_assert(dsp_reset);
313 if (ret) 340 if (ret)
314 goto free_rproc; 341 goto free_rproc;
315 342
diff --git a/drivers/remoteproc/qcom_adsp_pil.c b/drivers/remoteproc/qcom_adsp_pil.c
index 89a86ce07f99..d4339a6da616 100644
--- a/drivers/remoteproc/qcom_adsp_pil.c
+++ b/drivers/remoteproc/qcom_adsp_pil.c
@@ -31,6 +31,7 @@
31#include <linux/soc/qcom/smem_state.h> 31#include <linux/soc/qcom/smem_state.h>
32 32
33#include "qcom_common.h" 33#include "qcom_common.h"
34#include "qcom_q6v5.h"
34#include "remoteproc_internal.h" 35#include "remoteproc_internal.h"
35 36
36struct adsp_data { 37struct adsp_data {
@@ -48,14 +49,7 @@ struct qcom_adsp {
48 struct device *dev; 49 struct device *dev;
49 struct rproc *rproc; 50 struct rproc *rproc;
50 51
51 int wdog_irq; 52 struct qcom_q6v5 q6v5;
52 int fatal_irq;
53 int ready_irq;
54 int handover_irq;
55 int stop_ack_irq;
56
57 struct qcom_smem_state *state;
58 unsigned stop_bit;
59 53
60 struct clk *xo; 54 struct clk *xo;
61 struct clk *aggre2_clk; 55 struct clk *aggre2_clk;
@@ -96,6 +90,8 @@ static int adsp_start(struct rproc *rproc)
96 struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; 90 struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
97 int ret; 91 int ret;
98 92
93 qcom_q6v5_prepare(&adsp->q6v5);
94
99 ret = clk_prepare_enable(adsp->xo); 95 ret = clk_prepare_enable(adsp->xo);
100 if (ret) 96 if (ret)
101 return ret; 97 return ret;
@@ -119,16 +115,14 @@ static int adsp_start(struct rproc *rproc)
119 goto disable_px_supply; 115 goto disable_px_supply;
120 } 116 }
121 117
122 ret = wait_for_completion_timeout(&adsp->start_done, 118 ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5000));
123 msecs_to_jiffies(5000)); 119 if (ret == -ETIMEDOUT) {
124 if (!ret) {
125 dev_err(adsp->dev, "start timed out\n"); 120 dev_err(adsp->dev, "start timed out\n");
126 qcom_scm_pas_shutdown(adsp->pas_id); 121 qcom_scm_pas_shutdown(adsp->pas_id);
127 ret = -ETIMEDOUT;
128 goto disable_px_supply; 122 goto disable_px_supply;
129 } 123 }
130 124
131 ret = 0; 125 return 0;
132 126
133disable_px_supply: 127disable_px_supply:
134 regulator_disable(adsp->px_supply); 128 regulator_disable(adsp->px_supply);
@@ -142,28 +136,34 @@ disable_xo_clk:
142 return ret; 136 return ret;
143} 137}
144 138
139static void qcom_pas_handover(struct qcom_q6v5 *q6v5)
140{
141 struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5);
142
143 regulator_disable(adsp->px_supply);
144 regulator_disable(adsp->cx_supply);
145 clk_disable_unprepare(adsp->aggre2_clk);
146 clk_disable_unprepare(adsp->xo);
147}
148
145static int adsp_stop(struct rproc *rproc) 149static int adsp_stop(struct rproc *rproc)
146{ 150{
147 struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; 151 struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
152 int handover;
148 int ret; 153 int ret;
149 154
150 qcom_smem_state_update_bits(adsp->state, 155 ret = qcom_q6v5_request_stop(&adsp->q6v5);
151 BIT(adsp->stop_bit), 156 if (ret == -ETIMEDOUT)
152 BIT(adsp->stop_bit));
153
154 ret = wait_for_completion_timeout(&adsp->stop_done,
155 msecs_to_jiffies(5000));
156 if (ret == 0)
157 dev_err(adsp->dev, "timed out on wait\n"); 157 dev_err(adsp->dev, "timed out on wait\n");
158 158
159 qcom_smem_state_update_bits(adsp->state,
160 BIT(adsp->stop_bit),
161 0);
162
163 ret = qcom_scm_pas_shutdown(adsp->pas_id); 159 ret = qcom_scm_pas_shutdown(adsp->pas_id);
164 if (ret) 160 if (ret)
165 dev_err(adsp->dev, "failed to shutdown: %d\n", ret); 161 dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
166 162
163 handover = qcom_q6v5_unprepare(&adsp->q6v5);
164 if (handover)
165 qcom_pas_handover(&adsp->q6v5);
166
167 return ret; 167 return ret;
168} 168}
169 169
@@ -187,53 +187,6 @@ static const struct rproc_ops adsp_ops = {
187 .load = adsp_load, 187 .load = adsp_load,
188}; 188};
189 189
190static irqreturn_t adsp_wdog_interrupt(int irq, void *dev)
191{
192 struct qcom_adsp *adsp = dev;
193
194 rproc_report_crash(adsp->rproc, RPROC_WATCHDOG);
195
196 return IRQ_HANDLED;
197}
198
199static irqreturn_t adsp_fatal_interrupt(int irq, void *dev)
200{
201 struct qcom_adsp *adsp = dev;
202 size_t len;
203 char *msg;
204
205 msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, adsp->crash_reason_smem, &len);
206 if (!IS_ERR(msg) && len > 0 && msg[0])
207 dev_err(adsp->dev, "fatal error received: %s\n", msg);
208
209 rproc_report_crash(adsp->rproc, RPROC_FATAL_ERROR);
210
211 return IRQ_HANDLED;
212}
213
214static irqreturn_t adsp_ready_interrupt(int irq, void *dev)
215{
216 return IRQ_HANDLED;
217}
218
219static irqreturn_t adsp_handover_interrupt(int irq, void *dev)
220{
221 struct qcom_adsp *adsp = dev;
222
223 complete(&adsp->start_done);
224
225 return IRQ_HANDLED;
226}
227
228static irqreturn_t adsp_stop_ack_interrupt(int irq, void *dev)
229{
230 struct qcom_adsp *adsp = dev;
231
232 complete(&adsp->stop_done);
233
234 return IRQ_HANDLED;
235}
236
237static int adsp_init_clock(struct qcom_adsp *adsp) 190static int adsp_init_clock(struct qcom_adsp *adsp)
238{ 191{
239 int ret; 192 int ret;
@@ -272,29 +225,6 @@ static int adsp_init_regulator(struct qcom_adsp *adsp)
272 return PTR_ERR_OR_ZERO(adsp->px_supply); 225 return PTR_ERR_OR_ZERO(adsp->px_supply);
273} 226}
274 227
275static int adsp_request_irq(struct qcom_adsp *adsp,
276 struct platform_device *pdev,
277 const char *name,
278 irq_handler_t thread_fn)
279{
280 int ret;
281
282 ret = platform_get_irq_byname(pdev, name);
283 if (ret < 0) {
284 dev_err(&pdev->dev, "no %s IRQ defined\n", name);
285 return ret;
286 }
287
288 ret = devm_request_threaded_irq(&pdev->dev, ret,
289 NULL, thread_fn,
290 IRQF_ONESHOT,
291 "adsp", adsp);
292 if (ret)
293 dev_err(&pdev->dev, "request %s IRQ failed\n", name);
294
295 return ret;
296}
297
298static int adsp_alloc_memory_region(struct qcom_adsp *adsp) 228static int adsp_alloc_memory_region(struct qcom_adsp *adsp)
299{ 229{
300 struct device_node *node; 230 struct device_node *node;
@@ -348,13 +278,9 @@ static int adsp_probe(struct platform_device *pdev)
348 adsp->dev = &pdev->dev; 278 adsp->dev = &pdev->dev;
349 adsp->rproc = rproc; 279 adsp->rproc = rproc;
350 adsp->pas_id = desc->pas_id; 280 adsp->pas_id = desc->pas_id;
351 adsp->crash_reason_smem = desc->crash_reason_smem;
352 adsp->has_aggre2_clk = desc->has_aggre2_clk; 281 adsp->has_aggre2_clk = desc->has_aggre2_clk;
353 platform_set_drvdata(pdev, adsp); 282 platform_set_drvdata(pdev, adsp);
354 283
355 init_completion(&adsp->start_done);
356 init_completion(&adsp->stop_done);
357
358 ret = adsp_alloc_memory_region(adsp); 284 ret = adsp_alloc_memory_region(adsp);
359 if (ret) 285 if (ret)
360 goto free_rproc; 286 goto free_rproc;
@@ -367,37 +293,10 @@ static int adsp_probe(struct platform_device *pdev)
367 if (ret) 293 if (ret)
368 goto free_rproc; 294 goto free_rproc;
369 295
370 ret = adsp_request_irq(adsp, pdev, "wdog", adsp_wdog_interrupt); 296 ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem,
371 if (ret < 0) 297 qcom_pas_handover);
372 goto free_rproc; 298 if (ret)
373 adsp->wdog_irq = ret;
374
375 ret = adsp_request_irq(adsp, pdev, "fatal", adsp_fatal_interrupt);
376 if (ret < 0)
377 goto free_rproc;
378 adsp->fatal_irq = ret;
379
380 ret = adsp_request_irq(adsp, pdev, "ready", adsp_ready_interrupt);
381 if (ret < 0)
382 goto free_rproc;
383 adsp->ready_irq = ret;
384
385 ret = adsp_request_irq(adsp, pdev, "handover", adsp_handover_interrupt);
386 if (ret < 0)
387 goto free_rproc;
388 adsp->handover_irq = ret;
389
390 ret = adsp_request_irq(adsp, pdev, "stop-ack", adsp_stop_ack_interrupt);
391 if (ret < 0)
392 goto free_rproc;
393 adsp->stop_ack_irq = ret;
394
395 adsp->state = qcom_smem_state_get(&pdev->dev, "stop",
396 &adsp->stop_bit);
397 if (IS_ERR(adsp->state)) {
398 ret = PTR_ERR(adsp->state);
399 goto free_rproc; 299 goto free_rproc;
400 }
401 300
402 qcom_add_glink_subdev(rproc, &adsp->glink_subdev); 301 qcom_add_glink_subdev(rproc, &adsp->glink_subdev);
403 qcom_add_smd_subdev(rproc, &adsp->smd_subdev); 302 qcom_add_smd_subdev(rproc, &adsp->smd_subdev);
@@ -422,7 +321,6 @@ static int adsp_remove(struct platform_device *pdev)
422{ 321{
423 struct qcom_adsp *adsp = platform_get_drvdata(pdev); 322 struct qcom_adsp *adsp = platform_get_drvdata(pdev);
424 323
425 qcom_smem_state_put(adsp->state);
426 rproc_del(adsp->rproc); 324 rproc_del(adsp->rproc);
427 325
428 qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev); 326 qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c
index acfc99f82fb8..6f77840140bf 100644
--- a/drivers/remoteproc/qcom_common.c
+++ b/drivers/remoteproc/qcom_common.c
@@ -33,7 +33,7 @@
33 33
34static BLOCKING_NOTIFIER_HEAD(ssr_notifiers); 34static BLOCKING_NOTIFIER_HEAD(ssr_notifiers);
35 35
36static int glink_subdev_probe(struct rproc_subdev *subdev) 36static int glink_subdev_start(struct rproc_subdev *subdev)
37{ 37{
38 struct qcom_rproc_glink *glink = to_glink_subdev(subdev); 38 struct qcom_rproc_glink *glink = to_glink_subdev(subdev);
39 39
@@ -42,7 +42,7 @@ static int glink_subdev_probe(struct rproc_subdev *subdev)
42 return PTR_ERR_OR_ZERO(glink->edge); 42 return PTR_ERR_OR_ZERO(glink->edge);
43} 43}
44 44
45static void glink_subdev_remove(struct rproc_subdev *subdev, bool crashed) 45static void glink_subdev_stop(struct rproc_subdev *subdev, bool crashed)
46{ 46{
47 struct qcom_rproc_glink *glink = to_glink_subdev(subdev); 47 struct qcom_rproc_glink *glink = to_glink_subdev(subdev);
48 48
@@ -64,7 +64,10 @@ void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink)
64 return; 64 return;
65 65
66 glink->dev = dev; 66 glink->dev = dev;
67 rproc_add_subdev(rproc, &glink->subdev, glink_subdev_probe, glink_subdev_remove); 67 glink->subdev.start = glink_subdev_start;
68 glink->subdev.stop = glink_subdev_stop;
69
70 rproc_add_subdev(rproc, &glink->subdev);
68} 71}
69EXPORT_SYMBOL_GPL(qcom_add_glink_subdev); 72EXPORT_SYMBOL_GPL(qcom_add_glink_subdev);
70 73
@@ -126,7 +129,7 @@ int qcom_register_dump_segments(struct rproc *rproc,
126} 129}
127EXPORT_SYMBOL_GPL(qcom_register_dump_segments); 130EXPORT_SYMBOL_GPL(qcom_register_dump_segments);
128 131
129static int smd_subdev_probe(struct rproc_subdev *subdev) 132static int smd_subdev_start(struct rproc_subdev *subdev)
130{ 133{
131 struct qcom_rproc_subdev *smd = to_smd_subdev(subdev); 134 struct qcom_rproc_subdev *smd = to_smd_subdev(subdev);
132 135
@@ -135,7 +138,7 @@ static int smd_subdev_probe(struct rproc_subdev *subdev)
135 return PTR_ERR_OR_ZERO(smd->edge); 138 return PTR_ERR_OR_ZERO(smd->edge);
136} 139}
137 140
138static void smd_subdev_remove(struct rproc_subdev *subdev, bool crashed) 141static void smd_subdev_stop(struct rproc_subdev *subdev, bool crashed)
139{ 142{
140 struct qcom_rproc_subdev *smd = to_smd_subdev(subdev); 143 struct qcom_rproc_subdev *smd = to_smd_subdev(subdev);
141 144
@@ -157,7 +160,10 @@ void qcom_add_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd)
157 return; 160 return;
158 161
159 smd->dev = dev; 162 smd->dev = dev;
160 rproc_add_subdev(rproc, &smd->subdev, smd_subdev_probe, smd_subdev_remove); 163 smd->subdev.start = smd_subdev_start;
164 smd->subdev.stop = smd_subdev_stop;
165
166 rproc_add_subdev(rproc, &smd->subdev);
161} 167}
162EXPORT_SYMBOL_GPL(qcom_add_smd_subdev); 168EXPORT_SYMBOL_GPL(qcom_add_smd_subdev);
163 169
@@ -202,11 +208,6 @@ void qcom_unregister_ssr_notifier(struct notifier_block *nb)
202} 208}
203EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier); 209EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier);
204 210
205static int ssr_notify_start(struct rproc_subdev *subdev)
206{
207 return 0;
208}
209
210static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed) 211static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed)
211{ 212{
212 struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); 213 struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev);
@@ -227,8 +228,9 @@ void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr,
227 const char *ssr_name) 228 const char *ssr_name)
228{ 229{
229 ssr->name = ssr_name; 230 ssr->name = ssr_name;
231 ssr->subdev.stop = ssr_notify_stop;
230 232
231 rproc_add_subdev(rproc, &ssr->subdev, ssr_notify_start, ssr_notify_stop); 233 rproc_add_subdev(rproc, &ssr->subdev);
232} 234}
233EXPORT_SYMBOL_GPL(qcom_add_ssr_subdev); 235EXPORT_SYMBOL_GPL(qcom_add_ssr_subdev);
234 236
diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
new file mode 100644
index 000000000000..61a760ee4aac
--- /dev/null
+++ b/drivers/remoteproc/qcom_q6v5.c
@@ -0,0 +1,252 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Qualcomm Peripheral Image Loader for Q6V5
4 *
5 * Copyright (C) 2016-2018 Linaro Ltd.
6 * Copyright (C) 2014 Sony Mobile Communications AB
7 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
8 */
9#include <linux/kernel.h>
10#include <linux/platform_device.h>
11#include <linux/interrupt.h>
12#include <linux/module.h>
13#include <linux/soc/qcom/smem.h>
14#include <linux/soc/qcom/smem_state.h>
15#include <linux/remoteproc.h>
16#include "qcom_q6v5.h"
17
18/**
19 * qcom_q6v5_prepare() - reinitialize the qcom_q6v5 context before start
20 * @q6v5: reference to qcom_q6v5 context to be reinitialized
21 *
22 * Return: 0 on success, negative errno on failure
23 */
24int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5)
25{
26 reinit_completion(&q6v5->start_done);
27 reinit_completion(&q6v5->stop_done);
28
29 q6v5->running = true;
30 q6v5->handover_issued = false;
31
32 enable_irq(q6v5->handover_irq);
33
34 return 0;
35}
36EXPORT_SYMBOL_GPL(qcom_q6v5_prepare);
37
38/**
39 * qcom_q6v5_unprepare() - unprepare the qcom_q6v5 context after stop
40 * @q6v5: reference to qcom_q6v5 context to be unprepared
41 *
42 * Return: 0 on success, 1 if handover hasn't yet been called
43 */
44int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5)
45{
46 disable_irq(q6v5->handover_irq);
47
48 return !q6v5->handover_issued;
49}
50EXPORT_SYMBOL_GPL(qcom_q6v5_unprepare);
51
52static irqreturn_t q6v5_wdog_interrupt(int irq, void *data)
53{
54 struct qcom_q6v5 *q6v5 = data;
55 size_t len;
56 char *msg;
57
58 /* Sometimes the stop triggers a watchdog rather than a stop-ack */
59 if (!q6v5->running) {
60 complete(&q6v5->stop_done);
61 return IRQ_HANDLED;
62 }
63
64 msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len);
65 if (!IS_ERR(msg) && len > 0 && msg[0])
66 dev_err(q6v5->dev, "watchdog received: %s\n", msg);
67 else
68 dev_err(q6v5->dev, "watchdog without message\n");
69
70 rproc_report_crash(q6v5->rproc, RPROC_WATCHDOG);
71
72 return IRQ_HANDLED;
73}
74
75static irqreturn_t q6v5_fatal_interrupt(int irq, void *data)
76{
77 struct qcom_q6v5 *q6v5 = data;
78 size_t len;
79 char *msg;
80
81 msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len);
82 if (!IS_ERR(msg) && len > 0 && msg[0])
83 dev_err(q6v5->dev, "fatal error received: %s\n", msg);
84 else
85 dev_err(q6v5->dev, "fatal error without message\n");
86
87 rproc_report_crash(q6v5->rproc, RPROC_FATAL_ERROR);
88
89 return IRQ_HANDLED;
90}
91
92static irqreturn_t q6v5_ready_interrupt(int irq, void *data)
93{
94 struct qcom_q6v5 *q6v5 = data;
95
96 complete(&q6v5->start_done);
97
98 return IRQ_HANDLED;
99}
100
101/**
102 * qcom_q6v5_wait_for_start() - wait for remote processor start signal
103 * @q6v5: reference to qcom_q6v5 context
104 * @timeout: timeout to wait for the event, in jiffies
105 *
106 * qcom_q6v5_unprepare() should not be called when this function fails.
107 *
108 * Return: 0 on success, -ETIMEDOUT on timeout
109 */
110int qcom_q6v5_wait_for_start(struct qcom_q6v5 *q6v5, int timeout)
111{
112 int ret;
113
114 ret = wait_for_completion_timeout(&q6v5->start_done, timeout);
115 if (!ret)
116 disable_irq(q6v5->handover_irq);
117
118 return !ret ? -ETIMEDOUT : 0;
119}
120EXPORT_SYMBOL_GPL(qcom_q6v5_wait_for_start);
121
122static irqreturn_t q6v5_handover_interrupt(int irq, void *data)
123{
124 struct qcom_q6v5 *q6v5 = data;
125
126 if (q6v5->handover)
127 q6v5->handover(q6v5);
128
129 q6v5->handover_issued = true;
130
131 return IRQ_HANDLED;
132}
133
134static irqreturn_t q6v5_stop_interrupt(int irq, void *data)
135{
136 struct qcom_q6v5 *q6v5 = data;
137
138 complete(&q6v5->stop_done);
139
140 return IRQ_HANDLED;
141}
142
143/**
144 * qcom_q6v5_request_stop() - request the remote processor to stop
145 * @q6v5: reference to qcom_q6v5 context
146 *
147 * Return: 0 on success, negative errno on failure
148 */
149int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5)
150{
151 int ret;
152
153 q6v5->running = false;
154
155 qcom_smem_state_update_bits(q6v5->state,
156 BIT(q6v5->stop_bit), BIT(q6v5->stop_bit));
157
158 ret = wait_for_completion_timeout(&q6v5->stop_done, 5 * HZ);
159
160 qcom_smem_state_update_bits(q6v5->state, BIT(q6v5->stop_bit), 0);
161
162 return ret == 0 ? -ETIMEDOUT : 0;
163}
164EXPORT_SYMBOL_GPL(qcom_q6v5_request_stop);
165
166/**
167 * qcom_q6v5_init() - initializer of the q6v5 common struct
168 * @q6v5: handle to be initialized
169 * @pdev: platform_device reference for acquiring resources
170 * @rproc: associated remoteproc instance
171 * @crash_reason: SMEM id for crash reason string, or 0 if none
172 * @handover: function to be called when proxy resources should be released
173 *
174 * Return: 0 on success, negative errno on failure
175 */
176int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
177 struct rproc *rproc, int crash_reason,
178 void (*handover)(struct qcom_q6v5 *q6v5))
179{
180 int ret;
181
182 q6v5->rproc = rproc;
183 q6v5->dev = &pdev->dev;
184 q6v5->crash_reason = crash_reason;
185 q6v5->handover = handover;
186
187 init_completion(&q6v5->start_done);
188 init_completion(&q6v5->stop_done);
189
190 q6v5->wdog_irq = platform_get_irq_byname(pdev, "wdog");
191 ret = devm_request_threaded_irq(&pdev->dev, q6v5->wdog_irq,
192 NULL, q6v5_wdog_interrupt,
193 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
194 "q6v5 wdog", q6v5);
195 if (ret) {
196 dev_err(&pdev->dev, "failed to acquire wdog IRQ\n");
197 return ret;
198 }
199
200 q6v5->fatal_irq = platform_get_irq_byname(pdev, "fatal");
201 ret = devm_request_threaded_irq(&pdev->dev, q6v5->fatal_irq,
202 NULL, q6v5_fatal_interrupt,
203 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
204 "q6v5 fatal", q6v5);
205 if (ret) {
206 dev_err(&pdev->dev, "failed to acquire fatal IRQ\n");
207 return ret;
208 }
209
210 q6v5->ready_irq = platform_get_irq_byname(pdev, "ready");
211 ret = devm_request_threaded_irq(&pdev->dev, q6v5->ready_irq,
212 NULL, q6v5_ready_interrupt,
213 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
214 "q6v5 ready", q6v5);
215 if (ret) {
216 dev_err(&pdev->dev, "failed to acquire ready IRQ\n");
217 return ret;
218 }
219
220 q6v5->handover_irq = platform_get_irq_byname(pdev, "handover");
221 ret = devm_request_threaded_irq(&pdev->dev, q6v5->handover_irq,
222 NULL, q6v5_handover_interrupt,
223 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
224 "q6v5 handover", q6v5);
225 if (ret) {
226 dev_err(&pdev->dev, "failed to acquire handover IRQ\n");
227 return ret;
228 }
229 disable_irq(q6v5->handover_irq);
230
231 q6v5->stop_irq = platform_get_irq_byname(pdev, "stop-ack");
232 ret = devm_request_threaded_irq(&pdev->dev, q6v5->stop_irq,
233 NULL, q6v5_stop_interrupt,
234 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
235 "q6v5 stop", q6v5);
236 if (ret) {
237 dev_err(&pdev->dev, "failed to acquire stop-ack IRQ\n");
238 return ret;
239 }
240
241 q6v5->state = qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit);
242 if (IS_ERR(q6v5->state)) {
243 dev_err(&pdev->dev, "failed to acquire stop state\n");
244 return PTR_ERR(q6v5->state);
245 }
246
247 return 0;
248}
249EXPORT_SYMBOL_GPL(qcom_q6v5_init);
250
251MODULE_LICENSE("GPL v2");
252MODULE_DESCRIPTION("Qualcomm Peripheral Image Loader for Q6V5");
diff --git a/drivers/remoteproc/qcom_q6v5.h b/drivers/remoteproc/qcom_q6v5.h
new file mode 100644
index 000000000000..7ac92c1e0f49
--- /dev/null
+++ b/drivers/remoteproc/qcom_q6v5.h
@@ -0,0 +1,46 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2
3#ifndef __QCOM_Q6V5_H__
4#define __QCOM_Q6V5_H__
5
6#include <linux/kernel.h>
7#include <linux/completion.h>
8
9struct rproc;
10struct qcom_smem_state;
11
12struct qcom_q6v5 {
13 struct device *dev;
14 struct rproc *rproc;
15
16 struct qcom_smem_state *state;
17 unsigned stop_bit;
18
19 int wdog_irq;
20 int fatal_irq;
21 int ready_irq;
22 int handover_irq;
23 int stop_irq;
24
25 bool handover_issued;
26
27 struct completion start_done;
28 struct completion stop_done;
29
30 int crash_reason;
31
32 bool running;
33
34 void (*handover)(struct qcom_q6v5 *q6v5);
35};
36
37int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
38 struct rproc *rproc, int crash_reason,
39 void (*handover)(struct qcom_q6v5 *q6v5));
40
41int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5);
42int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5);
43int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5);
44int qcom_q6v5_wait_for_start(struct qcom_q6v5 *q6v5, int timeout);
45
46#endif
diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c
index 2bf8e7c49f2a..d7a4b9eca5d2 100644
--- a/drivers/remoteproc/qcom_q6v5_pil.c
+++ b/drivers/remoteproc/qcom_q6v5_pil.c
@@ -30,12 +30,11 @@
30#include <linux/remoteproc.h> 30#include <linux/remoteproc.h>
31#include <linux/reset.h> 31#include <linux/reset.h>
32#include <linux/soc/qcom/mdt_loader.h> 32#include <linux/soc/qcom/mdt_loader.h>
33#include <linux/soc/qcom/smem.h>
34#include <linux/soc/qcom/smem_state.h>
35#include <linux/iopoll.h> 33#include <linux/iopoll.h>
36 34
37#include "remoteproc_internal.h" 35#include "remoteproc_internal.h"
38#include "qcom_common.h" 36#include "qcom_common.h"
37#include "qcom_q6v5.h"
39 38
40#include <linux/qcom_scm.h> 39#include <linux/qcom_scm.h>
41 40
@@ -151,12 +150,7 @@ struct q6v5 {
151 150
152 struct reset_control *mss_restart; 151 struct reset_control *mss_restart;
153 152
154 struct qcom_smem_state *state; 153 struct qcom_q6v5 q6v5;
155 unsigned stop_bit;
156
157 int handover_irq;
158
159 bool proxy_unvoted;
160 154
161 struct clk *active_clks[8]; 155 struct clk *active_clks[8];
162 struct clk *reset_clks[4]; 156 struct clk *reset_clks[4];
@@ -170,8 +164,6 @@ struct q6v5 {
170 int active_reg_count; 164 int active_reg_count;
171 int proxy_reg_count; 165 int proxy_reg_count;
172 166
173 struct completion start_done;
174 struct completion stop_done;
175 bool running; 167 bool running;
176 168
177 phys_addr_t mba_phys; 169 phys_addr_t mba_phys;
@@ -798,9 +790,7 @@ static int q6v5_start(struct rproc *rproc)
798 int xfermemop_ret; 790 int xfermemop_ret;
799 int ret; 791 int ret;
800 792
801 qproc->proxy_unvoted = false; 793 qcom_q6v5_prepare(&qproc->q6v5);
802
803 enable_irq(qproc->handover_irq);
804 794
805 ret = q6v5_regulator_enable(qproc, qproc->proxy_regs, 795 ret = q6v5_regulator_enable(qproc, qproc->proxy_regs,
806 qproc->proxy_reg_count); 796 qproc->proxy_reg_count);
@@ -875,11 +865,9 @@ static int q6v5_start(struct rproc *rproc)
875 if (ret) 865 if (ret)
876 goto reclaim_mpss; 866 goto reclaim_mpss;
877 867
878 ret = wait_for_completion_timeout(&qproc->start_done, 868 ret = qcom_q6v5_wait_for_start(&qproc->q6v5, msecs_to_jiffies(5000));
879 msecs_to_jiffies(5000)); 869 if (ret == -ETIMEDOUT) {
880 if (ret == 0) {
881 dev_err(qproc->dev, "start timed out\n"); 870 dev_err(qproc->dev, "start timed out\n");
882 ret = -ETIMEDOUT;
883 goto reclaim_mpss; 871 goto reclaim_mpss;
884 } 872 }
885 873
@@ -933,7 +921,7 @@ disable_proxy_reg:
933 qproc->proxy_reg_count); 921 qproc->proxy_reg_count);
934 922
935disable_irqs: 923disable_irqs:
936 disable_irq(qproc->handover_irq); 924 qcom_q6v5_unprepare(&qproc->q6v5);
937 925
938 return ret; 926 return ret;
939} 927}
@@ -946,16 +934,10 @@ static int q6v5_stop(struct rproc *rproc)
946 934
947 qproc->running = false; 935 qproc->running = false;
948 936
949 qcom_smem_state_update_bits(qproc->state, 937 ret = qcom_q6v5_request_stop(&qproc->q6v5);
950 BIT(qproc->stop_bit), BIT(qproc->stop_bit)); 938 if (ret == -ETIMEDOUT)
951
952 ret = wait_for_completion_timeout(&qproc->stop_done,
953 msecs_to_jiffies(5000));
954 if (ret == 0)
955 dev_err(qproc->dev, "timed out on wait\n"); 939 dev_err(qproc->dev, "timed out on wait\n");
956 940
957 qcom_smem_state_update_bits(qproc->state, BIT(qproc->stop_bit), 0);
958
959 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6); 941 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
960 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); 942 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
961 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); 943 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
@@ -976,9 +958,8 @@ static int q6v5_stop(struct rproc *rproc)
976 958
977 q6v5_reset_assert(qproc); 959 q6v5_reset_assert(qproc);
978 960
979 disable_irq(qproc->handover_irq); 961 ret = qcom_q6v5_unprepare(&qproc->q6v5);
980 962 if (ret) {
981 if (!qproc->proxy_unvoted) {
982 q6v5_clk_disable(qproc->dev, qproc->proxy_clks, 963 q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
983 qproc->proxy_clk_count); 964 qproc->proxy_clk_count);
984 q6v5_regulator_disable(qproc, qproc->proxy_regs, 965 q6v5_regulator_disable(qproc, qproc->proxy_regs,
@@ -1014,74 +995,14 @@ static const struct rproc_ops q6v5_ops = {
1014 .load = q6v5_load, 995 .load = q6v5_load,
1015}; 996};
1016 997
1017static irqreturn_t q6v5_wdog_interrupt(int irq, void *dev) 998static void qcom_msa_handover(struct qcom_q6v5 *q6v5)
1018{
1019 struct q6v5 *qproc = dev;
1020 size_t len;
1021 char *msg;
1022
1023 /* Sometimes the stop triggers a watchdog rather than a stop-ack */
1024 if (!qproc->running) {
1025 complete(&qproc->stop_done);
1026 return IRQ_HANDLED;
1027 }
1028
1029 msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, MPSS_CRASH_REASON_SMEM, &len);
1030 if (!IS_ERR(msg) && len > 0 && msg[0])
1031 dev_err(qproc->dev, "watchdog received: %s\n", msg);
1032 else
1033 dev_err(qproc->dev, "watchdog without message\n");
1034
1035 rproc_report_crash(qproc->rproc, RPROC_WATCHDOG);
1036
1037 return IRQ_HANDLED;
1038}
1039
1040static irqreturn_t q6v5_fatal_interrupt(int irq, void *dev)
1041{
1042 struct q6v5 *qproc = dev;
1043 size_t len;
1044 char *msg;
1045
1046 msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, MPSS_CRASH_REASON_SMEM, &len);
1047 if (!IS_ERR(msg) && len > 0 && msg[0])
1048 dev_err(qproc->dev, "fatal error received: %s\n", msg);
1049 else
1050 dev_err(qproc->dev, "fatal error without message\n");
1051
1052 rproc_report_crash(qproc->rproc, RPROC_FATAL_ERROR);
1053
1054 return IRQ_HANDLED;
1055}
1056
1057static irqreturn_t q6v5_ready_interrupt(int irq, void *dev)
1058{
1059 struct q6v5 *qproc = dev;
1060
1061 complete(&qproc->start_done);
1062 return IRQ_HANDLED;
1063}
1064
1065static irqreturn_t q6v5_handover_interrupt(int irq, void *dev)
1066{ 999{
1067 struct q6v5 *qproc = dev; 1000 struct q6v5 *qproc = container_of(q6v5, struct q6v5, q6v5);
1068 1001
1069 q6v5_clk_disable(qproc->dev, qproc->proxy_clks, 1002 q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
1070 qproc->proxy_clk_count); 1003 qproc->proxy_clk_count);
1071 q6v5_regulator_disable(qproc, qproc->proxy_regs, 1004 q6v5_regulator_disable(qproc, qproc->proxy_regs,
1072 qproc->proxy_reg_count); 1005 qproc->proxy_reg_count);
1073
1074 qproc->proxy_unvoted = true;
1075
1076 return IRQ_HANDLED;
1077}
1078
1079static irqreturn_t q6v5_stop_ack_interrupt(int irq, void *dev)
1080{
1081 struct q6v5 *qproc = dev;
1082
1083 complete(&qproc->stop_done);
1084 return IRQ_HANDLED;
1085} 1006}
1086 1007
1087static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev) 1008static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev)
@@ -1154,30 +1075,6 @@ static int q6v5_init_reset(struct q6v5 *qproc)
1154 return 0; 1075 return 0;
1155} 1076}
1156 1077
1157static int q6v5_request_irq(struct q6v5 *qproc,
1158 struct platform_device *pdev,
1159 const char *name,
1160 irq_handler_t thread_fn)
1161{
1162 int irq;
1163 int ret;
1164
1165 irq = platform_get_irq_byname(pdev, name);
1166 if (irq < 0) {
1167 dev_err(&pdev->dev, "no %s IRQ defined\n", name);
1168 return irq;
1169 }
1170
1171 ret = devm_request_threaded_irq(&pdev->dev, irq,
1172 NULL, thread_fn,
1173 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
1174 "q6v5", qproc);
1175 if (ret)
1176 dev_err(&pdev->dev, "request %s IRQ failed\n", name);
1177
1178 return ret ? : irq;
1179}
1180
1181static int q6v5_alloc_memory_region(struct q6v5 *qproc) 1078static int q6v5_alloc_memory_region(struct q6v5 *qproc)
1182{ 1079{
1183 struct device_node *child; 1080 struct device_node *child;
@@ -1247,9 +1144,6 @@ static int q6v5_probe(struct platform_device *pdev)
1247 qproc->rproc = rproc; 1144 qproc->rproc = rproc;
1248 platform_set_drvdata(pdev, qproc); 1145 platform_set_drvdata(pdev, qproc);
1249 1146
1250 init_completion(&qproc->start_done);
1251 init_completion(&qproc->stop_done);
1252
1253 ret = q6v5_init_mem(qproc, pdev); 1147 ret = q6v5_init_mem(qproc, pdev);
1254 if (ret) 1148 if (ret)
1255 goto free_rproc; 1149 goto free_rproc;
@@ -1305,33 +1199,12 @@ static int q6v5_probe(struct platform_device *pdev)
1305 qproc->version = desc->version; 1199 qproc->version = desc->version;
1306 qproc->has_alt_reset = desc->has_alt_reset; 1200 qproc->has_alt_reset = desc->has_alt_reset;
1307 qproc->need_mem_protection = desc->need_mem_protection; 1201 qproc->need_mem_protection = desc->need_mem_protection;
1308 ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt);
1309 if (ret < 0)
1310 goto free_rproc;
1311 1202
1312 ret = q6v5_request_irq(qproc, pdev, "fatal", q6v5_fatal_interrupt); 1203 ret = qcom_q6v5_init(&qproc->q6v5, pdev, rproc, MPSS_CRASH_REASON_SMEM,
1313 if (ret < 0) 1204 qcom_msa_handover);
1314 goto free_rproc; 1205 if (ret)
1315
1316 ret = q6v5_request_irq(qproc, pdev, "ready", q6v5_ready_interrupt);
1317 if (ret < 0)
1318 goto free_rproc;
1319
1320 ret = q6v5_request_irq(qproc, pdev, "handover", q6v5_handover_interrupt);
1321 if (ret < 0)
1322 goto free_rproc;
1323 qproc->handover_irq = ret;
1324 disable_irq(qproc->handover_irq);
1325
1326 ret = q6v5_request_irq(qproc, pdev, "stop-ack", q6v5_stop_ack_interrupt);
1327 if (ret < 0)
1328 goto free_rproc; 1206 goto free_rproc;
1329 1207
1330 qproc->state = qcom_smem_state_get(&pdev->dev, "stop", &qproc->stop_bit);
1331 if (IS_ERR(qproc->state)) {
1332 ret = PTR_ERR(qproc->state);
1333 goto free_rproc;
1334 }
1335 qproc->mpss_perm = BIT(QCOM_SCM_VMID_HLOS); 1208 qproc->mpss_perm = BIT(QCOM_SCM_VMID_HLOS);
1336 qproc->mba_perm = BIT(QCOM_SCM_VMID_HLOS); 1209 qproc->mba_perm = BIT(QCOM_SCM_VMID_HLOS);
1337 qcom_add_glink_subdev(rproc, &qproc->glink_subdev); 1210 qcom_add_glink_subdev(rproc, &qproc->glink_subdev);
@@ -1370,7 +1243,6 @@ static const struct rproc_hexagon_res sdm845_mss = {
1370 .hexagon_mba_image = "mba.mbn", 1243 .hexagon_mba_image = "mba.mbn",
1371 .proxy_clk_names = (char*[]){ 1244 .proxy_clk_names = (char*[]){
1372 "xo", 1245 "xo",
1373 "axis2",
1374 "prng", 1246 "prng",
1375 NULL 1247 NULL
1376 }, 1248 },
diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c
new file mode 100644
index 000000000000..f93e1e4a1cc0
--- /dev/null
+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
@@ -0,0 +1,601 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2016-2018 Linaro Ltd.
4 * Copyright (C) 2014 Sony Mobile Communications AB
5 * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
6 */
7#include <linux/iopoll.h>
8#include <linux/kernel.h>
9#include <linux/mfd/syscon.h>
10#include <linux/module.h>
11#include <linux/of_reserved_mem.h>
12#include <linux/platform_device.h>
13#include <linux/regmap.h>
14#include <linux/reset.h>
15#include <linux/soc/qcom/mdt_loader.h>
16#include "qcom_common.h"
17#include "qcom_q6v5.h"
18
19#define WCSS_CRASH_REASON 421
20
21/* Q6SS Register Offsets */
22#define Q6SS_RESET_REG 0x014
23#define Q6SS_GFMUX_CTL_REG 0x020
24#define Q6SS_PWR_CTL_REG 0x030
25#define Q6SS_MEM_PWR_CTL 0x0B0
26
27/* AXI Halt Register Offsets */
28#define AXI_HALTREQ_REG 0x0
29#define AXI_HALTACK_REG 0x4
30#define AXI_IDLE_REG 0x8
31
32#define HALT_ACK_TIMEOUT_MS 100
33
34/* Q6SS_RESET */
35#define Q6SS_STOP_CORE BIT(0)
36#define Q6SS_CORE_ARES BIT(1)
37#define Q6SS_BUS_ARES_ENABLE BIT(2)
38
39/* Q6SS_GFMUX_CTL */
40#define Q6SS_CLK_ENABLE BIT(1)
41
42/* Q6SS_PWR_CTL */
43#define Q6SS_L2DATA_STBY_N BIT(18)
44#define Q6SS_SLP_RET_N BIT(19)
45#define Q6SS_CLAMP_IO BIT(20)
46#define QDSS_BHS_ON BIT(21)
47
48/* Q6SS parameters */
49#define Q6SS_LDO_BYP BIT(25)
50#define Q6SS_BHS_ON BIT(24)
51#define Q6SS_CLAMP_WL BIT(21)
52#define Q6SS_CLAMP_QMC_MEM BIT(22)
53#define HALT_CHECK_MAX_LOOPS 200
54#define Q6SS_XO_CBCR GENMASK(5, 3)
55
56/* Q6SS config/status registers */
57#define TCSR_GLOBAL_CFG0 0x0
58#define TCSR_GLOBAL_CFG1 0x4
59#define SSCAON_CONFIG 0x8
60#define SSCAON_STATUS 0xc
61#define Q6SS_BHS_STATUS 0x78
62#define Q6SS_RST_EVB 0x10
63
64#define BHS_EN_REST_ACK BIT(0)
65#define SSCAON_ENABLE BIT(13)
66#define SSCAON_BUS_EN BIT(15)
67#define SSCAON_BUS_MUX_MASK GENMASK(18, 16)
68
69#define MEM_BANKS 19
70#define TCSR_WCSS_CLK_MASK 0x1F
71#define TCSR_WCSS_CLK_ENABLE 0x14
72
73struct q6v5_wcss {
74 struct device *dev;
75
76 void __iomem *reg_base;
77 void __iomem *rmb_base;
78
79 struct regmap *halt_map;
80 u32 halt_q6;
81 u32 halt_wcss;
82 u32 halt_nc;
83
84 struct reset_control *wcss_aon_reset;
85 struct reset_control *wcss_reset;
86 struct reset_control *wcss_q6_reset;
87
88 struct qcom_q6v5 q6v5;
89
90 phys_addr_t mem_phys;
91 phys_addr_t mem_reloc;
92 void *mem_region;
93 size_t mem_size;
94};
95
96static int q6v5_wcss_reset(struct q6v5_wcss *wcss)
97{
98 int ret;
99 u32 val;
100 int i;
101
102 /* Assert resets, stop core */
103 val = readl(wcss->reg_base + Q6SS_RESET_REG);
104 val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE;
105 writel(val, wcss->reg_base + Q6SS_RESET_REG);
106
107 /* BHS require xo cbcr to be enabled */
108 val = readl(wcss->reg_base + Q6SS_XO_CBCR);
109 val |= 0x1;
110 writel(val, wcss->reg_base + Q6SS_XO_CBCR);
111
112 /* Read CLKOFF bit to go low indicating CLK is enabled */
113 ret = readl_poll_timeout(wcss->reg_base + Q6SS_XO_CBCR,
114 val, !(val & BIT(31)), 1,
115 HALT_CHECK_MAX_LOOPS);
116 if (ret) {
117 dev_err(wcss->dev,
118 "xo cbcr enabling timed out (rc:%d)\n", ret);
119 return ret;
120 }
121 /* Enable power block headswitch and wait for it to stabilize */
122 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
123 val |= Q6SS_BHS_ON;
124 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
125 udelay(1);
126
127 /* Put LDO in bypass mode */
128 val |= Q6SS_LDO_BYP;
129 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
130
131 /* Deassert Q6 compiler memory clamp */
132 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
133 val &= ~Q6SS_CLAMP_QMC_MEM;
134 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
135
136 /* Deassert memory peripheral sleep and L2 memory standby */
137 val |= Q6SS_L2DATA_STBY_N | Q6SS_SLP_RET_N;
138 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
139
140 /* Turn on L1, L2, ETB and JU memories 1 at a time */
141 val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
142 for (i = MEM_BANKS; i >= 0; i--) {
143 val |= BIT(i);
144 writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
145 /*
146 * Read back value to ensure the write is done then
147 * wait for 1us for both memory peripheral and data
148 * array to turn on.
149 */
150 val |= readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
151 udelay(1);
152 }
153 /* Remove word line clamp */
154 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
155 val &= ~Q6SS_CLAMP_WL;
156 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
157
158 /* Remove IO clamp */
159 val &= ~Q6SS_CLAMP_IO;
160 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
161
162 /* Bring core out of reset */
163 val = readl(wcss->reg_base + Q6SS_RESET_REG);
164 val &= ~Q6SS_CORE_ARES;
165 writel(val, wcss->reg_base + Q6SS_RESET_REG);
166
167 /* Turn on core clock */
168 val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
169 val |= Q6SS_CLK_ENABLE;
170 writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
171
172 /* Start core execution */
173 val = readl(wcss->reg_base + Q6SS_RESET_REG);
174 val &= ~Q6SS_STOP_CORE;
175 writel(val, wcss->reg_base + Q6SS_RESET_REG);
176
177 return 0;
178}
179
180static int q6v5_wcss_start(struct rproc *rproc)
181{
182 struct q6v5_wcss *wcss = rproc->priv;
183 int ret;
184
185 qcom_q6v5_prepare(&wcss->q6v5);
186
187 /* Release Q6 and WCSS reset */
188 ret = reset_control_deassert(wcss->wcss_reset);
189 if (ret) {
190 dev_err(wcss->dev, "wcss_reset failed\n");
191 return ret;
192 }
193
194 ret = reset_control_deassert(wcss->wcss_q6_reset);
195 if (ret) {
196 dev_err(wcss->dev, "wcss_q6_reset failed\n");
197 goto wcss_reset;
198 }
199
200 /* Lithium configuration - clock gating and bus arbitration */
201 ret = regmap_update_bits(wcss->halt_map,
202 wcss->halt_nc + TCSR_GLOBAL_CFG0,
203 TCSR_WCSS_CLK_MASK,
204 TCSR_WCSS_CLK_ENABLE);
205 if (ret)
206 goto wcss_q6_reset;
207
208 ret = regmap_update_bits(wcss->halt_map,
209 wcss->halt_nc + TCSR_GLOBAL_CFG1,
210 1, 0);
211 if (ret)
212 goto wcss_q6_reset;
213
214 /* Write bootaddr to EVB so that Q6WCSS will jump there after reset */
215 writel(rproc->bootaddr >> 4, wcss->reg_base + Q6SS_RST_EVB);
216
217 ret = q6v5_wcss_reset(wcss);
218 if (ret)
219 goto wcss_q6_reset;
220
221 ret = qcom_q6v5_wait_for_start(&wcss->q6v5, 5 * HZ);
222 if (ret == -ETIMEDOUT)
223 dev_err(wcss->dev, "start timed out\n");
224
225 return ret;
226
227wcss_q6_reset:
228 reset_control_assert(wcss->wcss_q6_reset);
229
230wcss_reset:
231 reset_control_assert(wcss->wcss_reset);
232
233 return ret;
234}
235
236static void q6v5_wcss_halt_axi_port(struct q6v5_wcss *wcss,
237 struct regmap *halt_map,
238 u32 offset)
239{
240 unsigned long timeout;
241 unsigned int val;
242 int ret;
243
244 /* Check if we're already idle */
245 ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
246 if (!ret && val)
247 return;
248
249 /* Assert halt request */
250 regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1);
251
252 /* Wait for halt */
253 timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS);
254 for (;;) {
255 ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val);
256 if (ret || val || time_after(jiffies, timeout))
257 break;
258
259 msleep(1);
260 }
261
262 ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
263 if (ret || !val)
264 dev_err(wcss->dev, "port failed halt\n");
265
266 /* Clear halt request (port will remain halted until reset) */
267 regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
268}
269
270static int q6v5_wcss_powerdown(struct q6v5_wcss *wcss)
271{
272 int ret;
273 u32 val;
274
275 /* 1 - Assert WCSS/Q6 HALTREQ */
276 q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_wcss);
277
278 /* 2 - Enable WCSSAON_CONFIG */
279 val = readl(wcss->rmb_base + SSCAON_CONFIG);
280 val |= SSCAON_ENABLE;
281 writel(val, wcss->rmb_base + SSCAON_CONFIG);
282
283 /* 3 - Set SSCAON_CONFIG */
284 val |= SSCAON_BUS_EN;
285 val &= ~SSCAON_BUS_MUX_MASK;
286 writel(val, wcss->rmb_base + SSCAON_CONFIG);
287
288 /* 4 - SSCAON_CONFIG 1 */
289 val |= BIT(1);
290 writel(val, wcss->rmb_base + SSCAON_CONFIG);
291
292 /* 5 - wait for SSCAON_STATUS */
293 ret = readl_poll_timeout(wcss->rmb_base + SSCAON_STATUS,
294 val, (val & 0xffff) == 0x400, 1000,
295 HALT_CHECK_MAX_LOOPS);
296 if (ret) {
297 dev_err(wcss->dev,
298 "can't get SSCAON_STATUS rc:%d)\n", ret);
299 return ret;
300 }
301
302 /* 6 - De-assert WCSS_AON reset */
303 reset_control_assert(wcss->wcss_aon_reset);
304
305 /* 7 - Disable WCSSAON_CONFIG 13 */
306 val = readl(wcss->rmb_base + SSCAON_CONFIG);
307 val &= ~SSCAON_ENABLE;
308 writel(val, wcss->rmb_base + SSCAON_CONFIG);
309
310 /* 8 - De-assert WCSS/Q6 HALTREQ */
311 reset_control_assert(wcss->wcss_reset);
312
313 return 0;
314}
315
316static int q6v5_q6_powerdown(struct q6v5_wcss *wcss)
317{
318 int ret;
319 u32 val;
320 int i;
321
322 /* 1 - Halt Q6 bus interface */
323 q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_q6);
324
325 /* 2 - Disable Q6 Core clock */
326 val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
327 val &= ~Q6SS_CLK_ENABLE;
328 writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
329
330 /* 3 - Clamp I/O */
331 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
332 val |= Q6SS_CLAMP_IO;
333 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
334
335 /* 4 - Clamp WL */
336 val |= QDSS_BHS_ON;
337 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
338
339 /* 5 - Clear Erase standby */
340 val &= ~Q6SS_L2DATA_STBY_N;
341 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
342
343 /* 6 - Clear Sleep RTN */
344 val &= ~Q6SS_SLP_RET_N;
345 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
346
347 /* 7 - turn off Q6 memory foot/head switch one bank at a time */
348 for (i = 0; i < 20; i++) {
349 val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
350 val &= ~BIT(i);
351 writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
352 mdelay(1);
353 }
354
355 /* 8 - Assert QMC memory RTN */
356 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
357 val |= Q6SS_CLAMP_QMC_MEM;
358 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
359
360 /* 9 - Turn off BHS */
361 val &= ~Q6SS_BHS_ON;
362 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
363 udelay(1);
364
365 /* 10 - Wait till BHS Reset is done */
366 ret = readl_poll_timeout(wcss->reg_base + Q6SS_BHS_STATUS,
367 val, !(val & BHS_EN_REST_ACK), 1000,
368 HALT_CHECK_MAX_LOOPS);
369 if (ret) {
370 dev_err(wcss->dev, "BHS_STATUS not OFF (rc:%d)\n", ret);
371 return ret;
372 }
373
374 /* 11 - Assert WCSS reset */
375 reset_control_assert(wcss->wcss_reset);
376
377 /* 12 - Assert Q6 reset */
378 reset_control_assert(wcss->wcss_q6_reset);
379
380 return 0;
381}
382
383static int q6v5_wcss_stop(struct rproc *rproc)
384{
385 struct q6v5_wcss *wcss = rproc->priv;
386 int ret;
387
388 /* WCSS powerdown */
389 ret = qcom_q6v5_request_stop(&wcss->q6v5);
390 if (ret == -ETIMEDOUT) {
391 dev_err(wcss->dev, "timed out on wait\n");
392 return ret;
393 }
394
395 ret = q6v5_wcss_powerdown(wcss);
396 if (ret)
397 return ret;
398
399 /* Q6 Power down */
400 ret = q6v5_q6_powerdown(wcss);
401 if (ret)
402 return ret;
403
404 qcom_q6v5_unprepare(&wcss->q6v5);
405
406 return 0;
407}
408
409static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
410{
411 struct q6v5_wcss *wcss = rproc->priv;
412 int offset;
413
414 offset = da - wcss->mem_reloc;
415 if (offset < 0 || offset + len > wcss->mem_size)
416 return NULL;
417
418 return wcss->mem_region + offset;
419}
420
421static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw)
422{
423 struct q6v5_wcss *wcss = rproc->priv;
424
425 return qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware,
426 0, wcss->mem_region, wcss->mem_phys,
427 wcss->mem_size, &wcss->mem_reloc);
428}
429
430static const struct rproc_ops q6v5_wcss_ops = {
431 .start = q6v5_wcss_start,
432 .stop = q6v5_wcss_stop,
433 .da_to_va = q6v5_wcss_da_to_va,
434 .load = q6v5_wcss_load,
435 .get_boot_addr = rproc_elf_get_boot_addr,
436};
437
438static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss)
439{
440 struct device *dev = wcss->dev;
441
442 wcss->wcss_aon_reset = devm_reset_control_get(dev, "wcss_aon_reset");
443 if (IS_ERR(wcss->wcss_aon_reset)) {
444 dev_err(wcss->dev, "unable to acquire wcss_aon_reset\n");
445 return PTR_ERR(wcss->wcss_aon_reset);
446 }
447
448 wcss->wcss_reset = devm_reset_control_get(dev, "wcss_reset");
449 if (IS_ERR(wcss->wcss_reset)) {
450 dev_err(wcss->dev, "unable to acquire wcss_reset\n");
451 return PTR_ERR(wcss->wcss_reset);
452 }
453
454 wcss->wcss_q6_reset = devm_reset_control_get(dev, "wcss_q6_reset");
455 if (IS_ERR(wcss->wcss_q6_reset)) {
456 dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n");
457 return PTR_ERR(wcss->wcss_q6_reset);
458 }
459
460 return 0;
461}
462
463static int q6v5_wcss_init_mmio(struct q6v5_wcss *wcss,
464 struct platform_device *pdev)
465{
466 struct of_phandle_args args;
467 struct resource *res;
468 int ret;
469
470 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6");
471 wcss->reg_base = devm_ioremap_resource(&pdev->dev, res);
472 if (IS_ERR(wcss->reg_base))
473 return PTR_ERR(wcss->reg_base);
474
475 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb");
476 wcss->rmb_base = devm_ioremap_resource(&pdev->dev, res);
477 if (IS_ERR(wcss->rmb_base))
478 return PTR_ERR(wcss->rmb_base);
479
480 ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
481 "qcom,halt-regs", 3, 0, &args);
482 if (ret < 0) {
483 dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
484 return -EINVAL;
485 }
486
487 wcss->halt_map = syscon_node_to_regmap(args.np);
488 of_node_put(args.np);
489 if (IS_ERR(wcss->halt_map))
490 return PTR_ERR(wcss->halt_map);
491
492 wcss->halt_q6 = args.args[0];
493 wcss->halt_wcss = args.args[1];
494 wcss->halt_nc = args.args[2];
495
496 return 0;
497}
498
499static int q6v5_alloc_memory_region(struct q6v5_wcss *wcss)
500{
501 struct reserved_mem *rmem = NULL;
502 struct device_node *node;
503 struct device *dev = wcss->dev;
504
505 node = of_parse_phandle(dev->of_node, "memory-region", 0);
506 if (node)
507 rmem = of_reserved_mem_lookup(node);
508 of_node_put(node);
509
510 if (!rmem) {
511 dev_err(dev, "unable to acquire memory-region\n");
512 return -EINVAL;
513 }
514
515 wcss->mem_phys = rmem->base;
516 wcss->mem_reloc = rmem->base;
517 wcss->mem_size = rmem->size;
518 wcss->mem_region = devm_ioremap_wc(dev, wcss->mem_phys, wcss->mem_size);
519 if (!wcss->mem_region) {
520 dev_err(dev, "unable to map memory region: %pa+%pa\n",
521 &rmem->base, &rmem->size);
522 return -EBUSY;
523 }
524
525 return 0;
526}
527
528static int q6v5_wcss_probe(struct platform_device *pdev)
529{
530 struct q6v5_wcss *wcss;
531 struct rproc *rproc;
532 int ret;
533
534 rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_wcss_ops,
535 "IPQ8074/q6_fw.mdt", sizeof(*wcss));
536 if (!rproc) {
537 dev_err(&pdev->dev, "failed to allocate rproc\n");
538 return -ENOMEM;
539 }
540
541 wcss = rproc->priv;
542 wcss->dev = &pdev->dev;
543
544 ret = q6v5_wcss_init_mmio(wcss, pdev);
545 if (ret)
546 goto free_rproc;
547
548 ret = q6v5_alloc_memory_region(wcss);
549 if (ret)
550 goto free_rproc;
551
552 ret = q6v5_wcss_init_reset(wcss);
553 if (ret)
554 goto free_rproc;
555
556 ret = qcom_q6v5_init(&wcss->q6v5, pdev, rproc, WCSS_CRASH_REASON, NULL);
557 if (ret)
558 goto free_rproc;
559
560 ret = rproc_add(rproc);
561 if (ret)
562 goto free_rproc;
563
564 platform_set_drvdata(pdev, rproc);
565
566 return 0;
567
568free_rproc:
569 rproc_free(rproc);
570
571 return ret;
572}
573
574static int q6v5_wcss_remove(struct platform_device *pdev)
575{
576 struct rproc *rproc = platform_get_drvdata(pdev);
577
578 rproc_del(rproc);
579 rproc_free(rproc);
580
581 return 0;
582}
583
584static const struct of_device_id q6v5_wcss_of_match[] = {
585 { .compatible = "qcom,ipq8074-wcss-pil" },
586 { },
587};
588MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match);
589
590static struct platform_driver q6v5_wcss_driver = {
591 .probe = q6v5_wcss_probe,
592 .remove = q6v5_wcss_remove,
593 .driver = {
594 .name = "qcom-q6v5-wcss-pil",
595 .of_match_table = q6v5_wcss_of_match,
596 },
597};
598module_platform_driver(q6v5_wcss_driver);
599
600MODULE_DESCRIPTION("Hexagon WCSS Peripheral Image Loader");
601MODULE_LICENSE("GPL v2");
diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c
index f085545d7da5..e976a602b015 100644
--- a/drivers/remoteproc/qcom_sysmon.c
+++ b/drivers/remoteproc/qcom_sysmon.c
@@ -469,7 +469,10 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
469 469
470 qmi_add_lookup(&sysmon->qmi, 43, 0, 0); 470 qmi_add_lookup(&sysmon->qmi, 43, 0, 0);
471 471
472 rproc_add_subdev(rproc, &sysmon->subdev, sysmon_start, sysmon_stop); 472 sysmon->subdev.start = sysmon_start;
473 sysmon->subdev.stop = sysmon_stop;
474
475 rproc_add_subdev(rproc, &sysmon->subdev);
473 476
474 sysmon->nb.notifier_call = sysmon_notify; 477 sysmon->nb.notifier_call = sysmon_notify;
475 blocking_notifier_chain_register(&sysmon_notifiers, &sysmon->nb); 478 blocking_notifier_chain_register(&sysmon_notifiers, &sysmon->nb);
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index a9609d971f7f..aa6206706fe3 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -241,7 +241,7 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
241 if (notifyid > rproc->max_notifyid) 241 if (notifyid > rproc->max_notifyid)
242 rproc->max_notifyid = notifyid; 242 rproc->max_notifyid = notifyid;
243 243
244 dev_dbg(dev, "vring%d: va %p dma %pad size 0x%x idr %d\n", 244 dev_dbg(dev, "vring%d: va %pK dma %pad size 0x%x idr %d\n",
245 i, va, &dma, size, notifyid); 245 i, va, &dma, size, notifyid);
246 246
247 rvring->va = va; 247 rvring->va = va;
@@ -301,14 +301,14 @@ void rproc_free_vring(struct rproc_vring *rvring)
301 rsc->vring[idx].notifyid = -1; 301 rsc->vring[idx].notifyid = -1;
302} 302}
303 303
304static int rproc_vdev_do_probe(struct rproc_subdev *subdev) 304static int rproc_vdev_do_start(struct rproc_subdev *subdev)
305{ 305{
306 struct rproc_vdev *rvdev = container_of(subdev, struct rproc_vdev, subdev); 306 struct rproc_vdev *rvdev = container_of(subdev, struct rproc_vdev, subdev);
307 307
308 return rproc_add_virtio_dev(rvdev, rvdev->id); 308 return rproc_add_virtio_dev(rvdev, rvdev->id);
309} 309}
310 310
311static void rproc_vdev_do_remove(struct rproc_subdev *subdev, bool crashed) 311static void rproc_vdev_do_stop(struct rproc_subdev *subdev, bool crashed)
312{ 312{
313 struct rproc_vdev *rvdev = container_of(subdev, struct rproc_vdev, subdev); 313 struct rproc_vdev *rvdev = container_of(subdev, struct rproc_vdev, subdev);
314 314
@@ -399,8 +399,10 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
399 399
400 list_add_tail(&rvdev->node, &rproc->rvdevs); 400 list_add_tail(&rvdev->node, &rproc->rvdevs);
401 401
402 rproc_add_subdev(rproc, &rvdev->subdev, 402 rvdev->subdev.start = rproc_vdev_do_start;
403 rproc_vdev_do_probe, rproc_vdev_do_remove); 403 rvdev->subdev.stop = rproc_vdev_do_stop;
404
405 rproc_add_subdev(rproc, &rvdev->subdev);
404 406
405 return 0; 407 return 0;
406 408
@@ -497,7 +499,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
497 499
498 rproc->num_traces++; 500 rproc->num_traces++;
499 501
500 dev_dbg(dev, "%s added: va %p, da 0x%x, len 0x%x\n", 502 dev_dbg(dev, "%s added: va %pK, da 0x%x, len 0x%x\n",
501 name, ptr, rsc->da, rsc->len); 503 name, ptr, rsc->da, rsc->len);
502 504
503 return 0; 505 return 0;
@@ -635,7 +637,7 @@ static int rproc_handle_carveout(struct rproc *rproc,
635 goto free_carv; 637 goto free_carv;
636 } 638 }
637 639
638 dev_dbg(dev, "carveout va %p, dma %pad, len 0x%x\n", 640 dev_dbg(dev, "carveout va %pK, dma %pad, len 0x%x\n",
639 va, &dma, rsc->len); 641 va, &dma, rsc->len);
640 642
641 /* 643 /*
@@ -774,32 +776,72 @@ static int rproc_handle_resources(struct rproc *rproc,
774 return ret; 776 return ret;
775} 777}
776 778
777static int rproc_probe_subdevices(struct rproc *rproc) 779static int rproc_prepare_subdevices(struct rproc *rproc)
778{ 780{
779 struct rproc_subdev *subdev; 781 struct rproc_subdev *subdev;
780 int ret; 782 int ret;
781 783
782 list_for_each_entry(subdev, &rproc->subdevs, node) { 784 list_for_each_entry(subdev, &rproc->subdevs, node) {
783 ret = subdev->probe(subdev); 785 if (subdev->prepare) {
784 if (ret) 786 ret = subdev->prepare(subdev);
785 goto unroll_registration; 787 if (ret)
788 goto unroll_preparation;
789 }
790 }
791
792 return 0;
793
794unroll_preparation:
795 list_for_each_entry_continue_reverse(subdev, &rproc->subdevs, node) {
796 if (subdev->unprepare)
797 subdev->unprepare(subdev);
798 }
799
800 return ret;
801}
802
803static int rproc_start_subdevices(struct rproc *rproc)
804{
805 struct rproc_subdev *subdev;
806 int ret;
807
808 list_for_each_entry(subdev, &rproc->subdevs, node) {
809 if (subdev->start) {
810 ret = subdev->start(subdev);
811 if (ret)
812 goto unroll_registration;
813 }
786 } 814 }
787 815
788 return 0; 816 return 0;
789 817
790unroll_registration: 818unroll_registration:
791 list_for_each_entry_continue_reverse(subdev, &rproc->subdevs, node) 819 list_for_each_entry_continue_reverse(subdev, &rproc->subdevs, node) {
792 subdev->remove(subdev, true); 820 if (subdev->stop)
821 subdev->stop(subdev, true);
822 }
793 823
794 return ret; 824 return ret;
795} 825}
796 826
797static void rproc_remove_subdevices(struct rproc *rproc, bool crashed) 827static void rproc_stop_subdevices(struct rproc *rproc, bool crashed)
798{ 828{
799 struct rproc_subdev *subdev; 829 struct rproc_subdev *subdev;
800 830
801 list_for_each_entry_reverse(subdev, &rproc->subdevs, node) 831 list_for_each_entry_reverse(subdev, &rproc->subdevs, node) {
802 subdev->remove(subdev, crashed); 832 if (subdev->stop)
833 subdev->stop(subdev, crashed);
834 }
835}
836
837static void rproc_unprepare_subdevices(struct rproc *rproc)
838{
839 struct rproc_subdev *subdev;
840
841 list_for_each_entry_reverse(subdev, &rproc->subdevs, node) {
842 if (subdev->unprepare)
843 subdev->unprepare(subdev);
844 }
803} 845}
804 846
805/** 847/**
@@ -894,20 +936,26 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
894 rproc->table_ptr = loaded_table; 936 rproc->table_ptr = loaded_table;
895 } 937 }
896 938
939 ret = rproc_prepare_subdevices(rproc);
940 if (ret) {
941 dev_err(dev, "failed to prepare subdevices for %s: %d\n",
942 rproc->name, ret);
943 goto reset_table_ptr;
944 }
945
897 /* power up the remote processor */ 946 /* power up the remote processor */
898 ret = rproc->ops->start(rproc); 947 ret = rproc->ops->start(rproc);
899 if (ret) { 948 if (ret) {
900 dev_err(dev, "can't start rproc %s: %d\n", rproc->name, ret); 949 dev_err(dev, "can't start rproc %s: %d\n", rproc->name, ret);
901 return ret; 950 goto unprepare_subdevices;
902 } 951 }
903 952
904 /* probe any subdevices for the remote processor */ 953 /* Start any subdevices for the remote processor */
905 ret = rproc_probe_subdevices(rproc); 954 ret = rproc_start_subdevices(rproc);
906 if (ret) { 955 if (ret) {
907 dev_err(dev, "failed to probe subdevices for %s: %d\n", 956 dev_err(dev, "failed to probe subdevices for %s: %d\n",
908 rproc->name, ret); 957 rproc->name, ret);
909 rproc->ops->stop(rproc); 958 goto stop_rproc;
910 return ret;
911 } 959 }
912 960
913 rproc->state = RPROC_RUNNING; 961 rproc->state = RPROC_RUNNING;
@@ -915,6 +963,15 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
915 dev_info(dev, "remote processor %s is now up\n", rproc->name); 963 dev_info(dev, "remote processor %s is now up\n", rproc->name);
916 964
917 return 0; 965 return 0;
966
967stop_rproc:
968 rproc->ops->stop(rproc);
969unprepare_subdevices:
970 rproc_unprepare_subdevices(rproc);
971reset_table_ptr:
972 rproc->table_ptr = rproc->cached_table;
973
974 return ret;
918} 975}
919 976
920/* 977/*
@@ -1014,8 +1071,8 @@ static int rproc_stop(struct rproc *rproc, bool crashed)
1014 struct device *dev = &rproc->dev; 1071 struct device *dev = &rproc->dev;
1015 int ret; 1072 int ret;
1016 1073
1017 /* remove any subdevices for the remote processor */ 1074 /* Stop any subdevices for the remote processor */
1018 rproc_remove_subdevices(rproc, crashed); 1075 rproc_stop_subdevices(rproc, crashed);
1019 1076
1020 /* the installed resource table is no longer accessible */ 1077 /* the installed resource table is no longer accessible */
1021 rproc->table_ptr = rproc->cached_table; 1078 rproc->table_ptr = rproc->cached_table;
@@ -1027,6 +1084,8 @@ static int rproc_stop(struct rproc *rproc, bool crashed)
1027 return ret; 1084 return ret;
1028 } 1085 }
1029 1086
1087 rproc_unprepare_subdevices(rproc);
1088
1030 rproc->state = RPROC_OFFLINE; 1089 rproc->state = RPROC_OFFLINE;
1031 1090
1032 dev_info(dev, "stopped remote processor %s\n", rproc->name); 1091 dev_info(dev, "stopped remote processor %s\n", rproc->name);
@@ -1657,17 +1716,11 @@ EXPORT_SYMBOL(rproc_del);
1657 * rproc_add_subdev() - add a subdevice to a remoteproc 1716 * rproc_add_subdev() - add a subdevice to a remoteproc
1658 * @rproc: rproc handle to add the subdevice to 1717 * @rproc: rproc handle to add the subdevice to
1659 * @subdev: subdev handle to register 1718 * @subdev: subdev handle to register
1660 * @probe: function to call when the rproc boots 1719 *
1661 * @remove: function to call when the rproc shuts down 1720 * Caller is responsible for populating optional subdevice function pointers.
1662 */ 1721 */
1663void rproc_add_subdev(struct rproc *rproc, 1722void rproc_add_subdev(struct rproc *rproc, struct rproc_subdev *subdev)
1664 struct rproc_subdev *subdev,
1665 int (*probe)(struct rproc_subdev *subdev),
1666 void (*remove)(struct rproc_subdev *subdev, bool crashed))
1667{ 1723{
1668 subdev->probe = probe;
1669 subdev->remove = remove;
1670
1671 list_add_tail(&subdev->node, &rproc->subdevs); 1724 list_add_tail(&subdev->node, &rproc->subdevs);
1672} 1725}
1673EXPORT_SYMBOL(rproc_add_subdev); 1726EXPORT_SYMBOL(rproc_add_subdev);
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
index a20488336aa0..a5c29f2764a3 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -231,7 +231,7 @@ static int rproc_rsc_table_show(struct seq_file *seq, void *p)
231 } 231 }
232 break; 232 break;
233 default: 233 default:
234 seq_printf(seq, "Unknown resource type found: %d [hdr: %p]\n", 234 seq_printf(seq, "Unknown resource type found: %d [hdr: %pK]\n",
235 hdr->type, hdr); 235 hdr->type, hdr);
236 break; 236 break;
237 } 237 }
@@ -260,7 +260,7 @@ static int rproc_carveouts_show(struct seq_file *seq, void *p)
260 260
261 list_for_each_entry(carveout, &rproc->carveouts, node) { 261 list_for_each_entry(carveout, &rproc->carveouts, node) {
262 seq_puts(seq, "Carveout memory entry:\n"); 262 seq_puts(seq, "Carveout memory entry:\n");
263 seq_printf(seq, "\tVirtual address: %p\n", carveout->va); 263 seq_printf(seq, "\tVirtual address: %pK\n", carveout->va);
264 seq_printf(seq, "\tDMA address: %pad\n", &carveout->dma); 264 seq_printf(seq, "\tDMA address: %pad\n", &carveout->dma);
265 seq_printf(seq, "\tDevice address: 0x%x\n", carveout->da); 265 seq_printf(seq, "\tDevice address: 0x%x\n", carveout->da);
266 seq_printf(seq, "\tLength: 0x%x Bytes\n\n", carveout->len); 266 seq_printf(seq, "\tLength: 0x%x Bytes\n\n", carveout->len);
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index b0633fd4c041..bbecd44df7e8 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -96,7 +96,7 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
96 size = vring_size(len, rvring->align); 96 size = vring_size(len, rvring->align);
97 memset(addr, 0, size); 97 memset(addr, 0, size);
98 98
99 dev_dbg(dev, "vring%d: va %p qsz %d notifyid %d\n", 99 dev_dbg(dev, "vring%d: va %pK qsz %d notifyid %d\n",
100 id, addr, len, rvring->notifyid); 100 id, addr, len, rvring->notifyid);
101 101
102 /* 102 /*
diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
index 1ffb1f0c43d6..d711d9430a4f 100644
--- a/drivers/remoteproc/st_slim_rproc.c
+++ b/drivers/remoteproc/st_slim_rproc.c
@@ -195,7 +195,8 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
195 } 195 }
196 } 196 }
197 197
198 dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va); 198 dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
199 da, len, va);
199 200
200 return va; 201 return va;
201} 202}
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index dc09d7ac905f..1c488024c698 100644
--- a/drivers/soc/qcom/mdt_loader.c
+++ b/drivers/soc/qcom/mdt_loader.c
@@ -74,23 +74,10 @@ ssize_t qcom_mdt_get_size(const struct firmware *fw)
74} 74}
75EXPORT_SYMBOL_GPL(qcom_mdt_get_size); 75EXPORT_SYMBOL_GPL(qcom_mdt_get_size);
76 76
77/** 77static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
78 * qcom_mdt_load() - load the firmware which header is loaded as fw 78 const char *firmware, int pas_id, void *mem_region,
79 * @dev: device handle to associate resources with 79 phys_addr_t mem_phys, size_t mem_size,
80 * @fw: firmware object for the mdt file 80 phys_addr_t *reloc_base, bool pas_init)
81 * @firmware: name of the firmware, for construction of segment file names
82 * @pas_id: PAS identifier
83 * @mem_region: allocated memory region to load firmware into
84 * @mem_phys: physical address of allocated memory region
85 * @mem_size: size of the allocated memory region
86 * @reloc_base: adjusted physical address after relocation
87 *
88 * Returns 0 on success, negative errno otherwise.
89 */
90int qcom_mdt_load(struct device *dev, const struct firmware *fw,
91 const char *firmware, int pas_id, void *mem_region,
92 phys_addr_t mem_phys, size_t mem_size,
93 phys_addr_t *reloc_base)
94{ 81{
95 const struct elf32_phdr *phdrs; 82 const struct elf32_phdr *phdrs;
96 const struct elf32_phdr *phdr; 83 const struct elf32_phdr *phdr;
@@ -121,10 +108,12 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw,
121 if (!fw_name) 108 if (!fw_name)
122 return -ENOMEM; 109 return -ENOMEM;
123 110
124 ret = qcom_scm_pas_init_image(pas_id, fw->data, fw->size); 111 if (pas_init) {
125 if (ret) { 112 ret = qcom_scm_pas_init_image(pas_id, fw->data, fw->size);
126 dev_err(dev, "invalid firmware metadata\n"); 113 if (ret) {
127 goto out; 114 dev_err(dev, "invalid firmware metadata\n");
115 goto out;
116 }
128 } 117 }
129 118
130 for (i = 0; i < ehdr->e_phnum; i++) { 119 for (i = 0; i < ehdr->e_phnum; i++) {
@@ -144,10 +133,13 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw,
144 } 133 }
145 134
146 if (relocate) { 135 if (relocate) {
147 ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr); 136 if (pas_init) {
148 if (ret) { 137 ret = qcom_scm_pas_mem_setup(pas_id, mem_phys,
149 dev_err(dev, "unable to setup relocation\n"); 138 max_addr - min_addr);
150 goto out; 139 if (ret) {
140 dev_err(dev, "unable to setup relocation\n");
141 goto out;
142 }
151 } 143 }
152 144
153 /* 145 /*
@@ -202,7 +194,52 @@ out:
202 194
203 return ret; 195 return ret;
204} 196}
197
198/**
199 * qcom_mdt_load() - load the firmware which header is loaded as fw
200 * @dev: device handle to associate resources with
201 * @fw: firmware object for the mdt file
202 * @firmware: name of the firmware, for construction of segment file names
203 * @pas_id: PAS identifier
204 * @mem_region: allocated memory region to load firmware into
205 * @mem_phys: physical address of allocated memory region
206 * @mem_size: size of the allocated memory region
207 * @reloc_base: adjusted physical address after relocation
208 *
209 * Returns 0 on success, negative errno otherwise.
210 */
211int qcom_mdt_load(struct device *dev, const struct firmware *fw,
212 const char *firmware, int pas_id, void *mem_region,
213 phys_addr_t mem_phys, size_t mem_size,
214 phys_addr_t *reloc_base)
215{
216 return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys,
217 mem_size, reloc_base, true);
218}
205EXPORT_SYMBOL_GPL(qcom_mdt_load); 219EXPORT_SYMBOL_GPL(qcom_mdt_load);
206 220
221/**
222 * qcom_mdt_load_no_init() - load the firmware which header is loaded as fw
223 * @dev: device handle to associate resources with
224 * @fw: firmware object for the mdt file
225 * @firmware: name of the firmware, for construction of segment file names
226 * @pas_id: PAS identifier
227 * @mem_region: allocated memory region to load firmware into
228 * @mem_phys: physical address of allocated memory region
229 * @mem_size: size of the allocated memory region
230 * @reloc_base: adjusted physical address after relocation
231 *
232 * Returns 0 on success, negative errno otherwise.
233 */
234int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw,
235 const char *firmware, int pas_id,
236 void *mem_region, phys_addr_t mem_phys,
237 size_t mem_size, phys_addr_t *reloc_base)
238{
239 return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys,
240 mem_size, reloc_base, false);
241}
242EXPORT_SYMBOL_GPL(qcom_mdt_load_no_init);
243
207MODULE_DESCRIPTION("Firmware parser for Qualcomm MDT format"); 244MODULE_DESCRIPTION("Firmware parser for Qualcomm MDT format");
208MODULE_LICENSE("GPL v2"); 245MODULE_LICENSE("GPL v2");
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index dfdaede9139e..e3c5d856b6da 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -477,15 +477,19 @@ struct rproc {
477/** 477/**
478 * struct rproc_subdev - subdevice tied to a remoteproc 478 * struct rproc_subdev - subdevice tied to a remoteproc
479 * @node: list node related to the rproc subdevs list 479 * @node: list node related to the rproc subdevs list
480 * @probe: probe function, called as the rproc is started 480 * @prepare: prepare function, called before the rproc is started
481 * @remove: remove function, called as the rproc is being stopped, the @crashed 481 * @start: start function, called after the rproc has been started
482 * parameter indicates if this originates from the a recovery 482 * @stop: stop function, called before the rproc is stopped; the @crashed
483 * parameter indicates if this originates from a recovery
484 * @unprepare: unprepare function, called after the rproc has been stopped
483 */ 485 */
484struct rproc_subdev { 486struct rproc_subdev {
485 struct list_head node; 487 struct list_head node;
486 488
487 int (*probe)(struct rproc_subdev *subdev); 489 int (*prepare)(struct rproc_subdev *subdev);
488 void (*remove)(struct rproc_subdev *subdev, bool crashed); 490 int (*start)(struct rproc_subdev *subdev);
491 void (*stop)(struct rproc_subdev *subdev, bool crashed);
492 void (*unprepare)(struct rproc_subdev *subdev);
489}; 493};
490 494
491/* we currently support only two vrings per rvdev */ 495/* we currently support only two vrings per rvdev */
@@ -566,10 +570,7 @@ static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev)
566 return rvdev->rproc; 570 return rvdev->rproc;
567} 571}
568 572
569void rproc_add_subdev(struct rproc *rproc, 573void rproc_add_subdev(struct rproc *rproc, struct rproc_subdev *subdev);
570 struct rproc_subdev *subdev,
571 int (*probe)(struct rproc_subdev *subdev),
572 void (*remove)(struct rproc_subdev *subdev, bool crashed));
573 574
574void rproc_remove_subdev(struct rproc *rproc, struct rproc_subdev *subdev); 575void rproc_remove_subdev(struct rproc *rproc, struct rproc_subdev *subdev);
575 576
diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h
index 5b98bbdabc25..944b06aefb0f 100644
--- a/include/linux/soc/qcom/mdt_loader.h
+++ b/include/linux/soc/qcom/mdt_loader.h
@@ -17,4 +17,8 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw,
17 phys_addr_t mem_phys, size_t mem_size, 17 phys_addr_t mem_phys, size_t mem_size,
18 phys_addr_t *reloc_base); 18 phys_addr_t *reloc_base);
19 19
20int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw,
21 const char *fw_name, int pas_id, void *mem_region,
22 phys_addr_t mem_phys, size_t mem_size,
23 phys_addr_t *reloc_base);
20#endif 24#endif