diff options
Diffstat (limited to 'drivers/remoteproc/stm32_rproc.c')
-rw-r--r-- | drivers/remoteproc/stm32_rproc.c | 628 |
1 files changed, 628 insertions, 0 deletions
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c new file mode 100644 index 000000000000..e83077b9ebf5 --- /dev/null +++ b/drivers/remoteproc/stm32_rproc.c | |||
@@ -0,0 +1,628 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright (C) STMicroelectronics 2018 - All Rights Reserved | ||
4 | * Authors: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics. | ||
5 | * Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics. | ||
6 | */ | ||
7 | |||
8 | #include <linux/arm-smccc.h> | ||
9 | #include <linux/dma-mapping.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/io.h> | ||
12 | #include <linux/mailbox_client.h> | ||
13 | #include <linux/mfd/syscon.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/of_address.h> | ||
16 | #include <linux/of_device.h> | ||
17 | #include <linux/of_reserved_mem.h> | ||
18 | #include <linux/regmap.h> | ||
19 | #include <linux/remoteproc.h> | ||
20 | #include <linux/reset.h> | ||
21 | |||
22 | #include "remoteproc_internal.h" | ||
23 | |||
24 | #define HOLD_BOOT 0 | ||
25 | #define RELEASE_BOOT 1 | ||
26 | |||
27 | #define MBOX_NB_VQ 2 | ||
28 | #define MBOX_NB_MBX 3 | ||
29 | |||
30 | #define STM32_SMC_RCC 0x82001000 | ||
31 | #define STM32_SMC_REG_WRITE 0x1 | ||
32 | |||
33 | #define STM32_MBX_VQ0 "vq0" | ||
34 | #define STM32_MBX_VQ1 "vq1" | ||
35 | #define STM32_MBX_SHUTDOWN "shutdown" | ||
36 | |||
37 | struct stm32_syscon { | ||
38 | struct regmap *map; | ||
39 | u32 reg; | ||
40 | u32 mask; | ||
41 | }; | ||
42 | |||
43 | struct stm32_rproc_mem { | ||
44 | char name[20]; | ||
45 | void __iomem *cpu_addr; | ||
46 | phys_addr_t bus_addr; | ||
47 | u32 dev_addr; | ||
48 | size_t size; | ||
49 | }; | ||
50 | |||
51 | struct stm32_rproc_mem_ranges { | ||
52 | u32 dev_addr; | ||
53 | u32 bus_addr; | ||
54 | u32 size; | ||
55 | }; | ||
56 | |||
57 | struct stm32_mbox { | ||
58 | const unsigned char name[10]; | ||
59 | struct mbox_chan *chan; | ||
60 | struct mbox_client client; | ||
61 | int vq_id; | ||
62 | }; | ||
63 | |||
64 | struct stm32_rproc { | ||
65 | struct reset_control *rst; | ||
66 | struct stm32_syscon hold_boot; | ||
67 | struct stm32_syscon pdds; | ||
68 | u32 nb_rmems; | ||
69 | struct stm32_rproc_mem *rmems; | ||
70 | struct stm32_mbox mb[MBOX_NB_MBX]; | ||
71 | bool secured_soc; | ||
72 | }; | ||
73 | |||
74 | static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da) | ||
75 | { | ||
76 | unsigned int i; | ||
77 | struct stm32_rproc *ddata = rproc->priv; | ||
78 | struct stm32_rproc_mem *p_mem; | ||
79 | |||
80 | for (i = 0; i < ddata->nb_rmems; i++) { | ||
81 | p_mem = &ddata->rmems[i]; | ||
82 | |||
83 | if (pa < p_mem->bus_addr || | ||
84 | pa >= p_mem->bus_addr + p_mem->size) | ||
85 | continue; | ||
86 | *da = pa - p_mem->bus_addr + p_mem->dev_addr; | ||
87 | dev_dbg(rproc->dev.parent, "pa %pa to da %llx\n", &pa, *da); | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | return -EINVAL; | ||
92 | } | ||
93 | |||
94 | static int stm32_rproc_mem_alloc(struct rproc *rproc, | ||
95 | struct rproc_mem_entry *mem) | ||
96 | { | ||
97 | struct device *dev = rproc->dev.parent; | ||
98 | void *va; | ||
99 | |||
100 | dev_dbg(dev, "map memory: %pa+%x\n", &mem->dma, mem->len); | ||
101 | va = ioremap_wc(mem->dma, mem->len); | ||
102 | if (IS_ERR_OR_NULL(va)) { | ||
103 | dev_err(dev, "Unable to map memory region: %pa+%x\n", | ||
104 | &mem->dma, mem->len); | ||
105 | return -ENOMEM; | ||
106 | } | ||
107 | |||
108 | /* Update memory entry va */ | ||
109 | mem->va = va; | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int stm32_rproc_mem_release(struct rproc *rproc, | ||
115 | struct rproc_mem_entry *mem) | ||
116 | { | ||
117 | dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma); | ||
118 | iounmap(mem->va); | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static int stm32_rproc_of_memory_translations(struct rproc *rproc) | ||
124 | { | ||
125 | struct device *parent, *dev = rproc->dev.parent; | ||
126 | struct stm32_rproc *ddata = rproc->priv; | ||
127 | struct device_node *np; | ||
128 | struct stm32_rproc_mem *p_mems; | ||
129 | struct stm32_rproc_mem_ranges *mem_range; | ||
130 | int cnt, array_size, i, ret = 0; | ||
131 | |||
132 | parent = dev->parent; | ||
133 | np = parent->of_node; | ||
134 | |||
135 | cnt = of_property_count_elems_of_size(np, "dma-ranges", | ||
136 | sizeof(*mem_range)); | ||
137 | if (cnt <= 0) { | ||
138 | dev_err(dev, "%s: dma-ranges property not defined\n", __func__); | ||
139 | return -EINVAL; | ||
140 | } | ||
141 | |||
142 | p_mems = devm_kcalloc(dev, cnt, sizeof(*p_mems), GFP_KERNEL); | ||
143 | if (!p_mems) | ||
144 | return -ENOMEM; | ||
145 | mem_range = kcalloc(cnt, sizeof(*mem_range), GFP_KERNEL); | ||
146 | if (!mem_range) | ||
147 | return -ENOMEM; | ||
148 | |||
149 | array_size = cnt * sizeof(struct stm32_rproc_mem_ranges) / sizeof(u32); | ||
150 | |||
151 | ret = of_property_read_u32_array(np, "dma-ranges", | ||
152 | (u32 *)mem_range, array_size); | ||
153 | if (ret) { | ||
154 | dev_err(dev, "error while get dma-ranges property: %x\n", ret); | ||
155 | goto free_mem; | ||
156 | } | ||
157 | |||
158 | for (i = 0; i < cnt; i++) { | ||
159 | p_mems[i].bus_addr = mem_range[i].bus_addr; | ||
160 | p_mems[i].dev_addr = mem_range[i].dev_addr; | ||
161 | p_mems[i].size = mem_range[i].size; | ||
162 | |||
163 | dev_dbg(dev, "memory range[%i]: da %#x, pa %pa, size %#zx:\n", | ||
164 | i, p_mems[i].dev_addr, &p_mems[i].bus_addr, | ||
165 | p_mems[i].size); | ||
166 | } | ||
167 | |||
168 | ddata->rmems = p_mems; | ||
169 | ddata->nb_rmems = cnt; | ||
170 | |||
171 | free_mem: | ||
172 | kfree(mem_range); | ||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name) | ||
177 | { | ||
178 | struct stm32_rproc *ddata = rproc->priv; | ||
179 | int i; | ||
180 | |||
181 | for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) { | ||
182 | if (!strncmp(ddata->mb[i].name, name, strlen(name))) | ||
183 | return i; | ||
184 | } | ||
185 | dev_err(&rproc->dev, "mailbox %s not found\n", name); | ||
186 | |||
187 | return -EINVAL; | ||
188 | } | ||
189 | |||
190 | static int stm32_rproc_elf_load_rsc_table(struct rproc *rproc, | ||
191 | const struct firmware *fw) | ||
192 | { | ||
193 | if (rproc_elf_load_rsc_table(rproc, fw)) | ||
194 | dev_warn(&rproc->dev, "no resource table found for this firmware\n"); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) | ||
200 | { | ||
201 | struct device *dev = rproc->dev.parent; | ||
202 | struct device_node *np = dev->of_node; | ||
203 | struct of_phandle_iterator it; | ||
204 | struct rproc_mem_entry *mem; | ||
205 | struct reserved_mem *rmem; | ||
206 | u64 da; | ||
207 | int index = 0; | ||
208 | |||
209 | /* Register associated reserved memory regions */ | ||
210 | of_phandle_iterator_init(&it, np, "memory-region", NULL, 0); | ||
211 | while (of_phandle_iterator_next(&it) == 0) { | ||
212 | rmem = of_reserved_mem_lookup(it.node); | ||
213 | if (!rmem) { | ||
214 | dev_err(dev, "unable to acquire memory-region\n"); | ||
215 | return -EINVAL; | ||
216 | } | ||
217 | |||
218 | if (stm32_rproc_pa_to_da(rproc, rmem->base, &da) < 0) { | ||
219 | dev_err(dev, "memory region not valid %pa\n", | ||
220 | &rmem->base); | ||
221 | return -EINVAL; | ||
222 | } | ||
223 | |||
224 | /* No need to map vdev buffer */ | ||
225 | if (strcmp(it.node->name, "vdev0buffer")) { | ||
226 | /* Register memory region */ | ||
227 | mem = rproc_mem_entry_init(dev, NULL, | ||
228 | (dma_addr_t)rmem->base, | ||
229 | rmem->size, da, | ||
230 | stm32_rproc_mem_alloc, | ||
231 | stm32_rproc_mem_release, | ||
232 | it.node->name); | ||
233 | |||
234 | if (mem) | ||
235 | rproc_coredump_add_segment(rproc, da, | ||
236 | rmem->size); | ||
237 | } else { | ||
238 | /* Register reserved memory for vdev buffer alloc */ | ||
239 | mem = rproc_of_resm_mem_entry_init(dev, index, | ||
240 | rmem->size, | ||
241 | rmem->base, | ||
242 | it.node->name); | ||
243 | } | ||
244 | |||
245 | if (!mem) | ||
246 | return -ENOMEM; | ||
247 | |||
248 | rproc_add_carveout(rproc, mem); | ||
249 | index++; | ||
250 | } | ||
251 | |||
252 | return stm32_rproc_elf_load_rsc_table(rproc, fw); | ||
253 | } | ||
254 | |||
255 | static irqreturn_t stm32_rproc_wdg(int irq, void *data) | ||
256 | { | ||
257 | struct rproc *rproc = data; | ||
258 | |||
259 | rproc_report_crash(rproc, RPROC_WATCHDOG); | ||
260 | |||
261 | return IRQ_HANDLED; | ||
262 | } | ||
263 | |||
264 | static void stm32_rproc_mb_callback(struct mbox_client *cl, void *data) | ||
265 | { | ||
266 | struct rproc *rproc = dev_get_drvdata(cl->dev); | ||
267 | struct stm32_mbox *mb = container_of(cl, struct stm32_mbox, client); | ||
268 | |||
269 | if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE) | ||
270 | dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id); | ||
271 | } | ||
272 | |||
273 | static void stm32_rproc_free_mbox(struct rproc *rproc) | ||
274 | { | ||
275 | struct stm32_rproc *ddata = rproc->priv; | ||
276 | unsigned int i; | ||
277 | |||
278 | for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) { | ||
279 | if (ddata->mb[i].chan) | ||
280 | mbox_free_channel(ddata->mb[i].chan); | ||
281 | ddata->mb[i].chan = NULL; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = { | ||
286 | { | ||
287 | .name = STM32_MBX_VQ0, | ||
288 | .vq_id = 0, | ||
289 | .client = { | ||
290 | .rx_callback = stm32_rproc_mb_callback, | ||
291 | .tx_block = false, | ||
292 | }, | ||
293 | }, | ||
294 | { | ||
295 | .name = STM32_MBX_VQ1, | ||
296 | .vq_id = 1, | ||
297 | .client = { | ||
298 | .rx_callback = stm32_rproc_mb_callback, | ||
299 | .tx_block = false, | ||
300 | }, | ||
301 | }, | ||
302 | { | ||
303 | .name = STM32_MBX_SHUTDOWN, | ||
304 | .vq_id = -1, | ||
305 | .client = { | ||
306 | .tx_block = true, | ||
307 | .tx_done = NULL, | ||
308 | .tx_tout = 500, /* 500 ms time out */ | ||
309 | }, | ||
310 | } | ||
311 | }; | ||
312 | |||
313 | static void stm32_rproc_request_mbox(struct rproc *rproc) | ||
314 | { | ||
315 | struct stm32_rproc *ddata = rproc->priv; | ||
316 | struct device *dev = &rproc->dev; | ||
317 | unsigned int i; | ||
318 | const unsigned char *name; | ||
319 | struct mbox_client *cl; | ||
320 | |||
321 | /* Initialise mailbox structure table */ | ||
322 | memcpy(ddata->mb, stm32_rproc_mbox, sizeof(stm32_rproc_mbox)); | ||
323 | |||
324 | for (i = 0; i < MBOX_NB_MBX; i++) { | ||
325 | name = ddata->mb[i].name; | ||
326 | |||
327 | cl = &ddata->mb[i].client; | ||
328 | cl->dev = dev->parent; | ||
329 | |||
330 | ddata->mb[i].chan = mbox_request_channel_byname(cl, name); | ||
331 | if (IS_ERR(ddata->mb[i].chan)) { | ||
332 | dev_warn(dev, "cannot get %s mbox\n", name); | ||
333 | ddata->mb[i].chan = NULL; | ||
334 | } | ||
335 | } | ||
336 | } | ||
337 | |||
338 | static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold) | ||
339 | { | ||
340 | struct stm32_rproc *ddata = rproc->priv; | ||
341 | struct stm32_syscon hold_boot = ddata->hold_boot; | ||
342 | struct arm_smccc_res smc_res; | ||
343 | int val, err; | ||
344 | |||
345 | val = hold ? HOLD_BOOT : RELEASE_BOOT; | ||
346 | |||
347 | if (ddata->secured_soc) { | ||
348 | arm_smccc_smc(STM32_SMC_RCC, STM32_SMC_REG_WRITE, | ||
349 | hold_boot.reg, val, 0, 0, 0, 0, &smc_res); | ||
350 | err = smc_res.a0; | ||
351 | } else { | ||
352 | err = regmap_update_bits(hold_boot.map, hold_boot.reg, | ||
353 | hold_boot.mask, val); | ||
354 | } | ||
355 | |||
356 | if (err) | ||
357 | dev_err(&rproc->dev, "failed to set hold boot\n"); | ||
358 | |||
359 | return err; | ||
360 | } | ||
361 | |||
362 | static void stm32_rproc_add_coredump_trace(struct rproc *rproc) | ||
363 | { | ||
364 | struct rproc_debug_trace *trace; | ||
365 | struct rproc_dump_segment *segment; | ||
366 | bool already_added; | ||
367 | |||
368 | list_for_each_entry(trace, &rproc->traces, node) { | ||
369 | already_added = false; | ||
370 | |||
371 | list_for_each_entry(segment, &rproc->dump_segments, node) { | ||
372 | if (segment->da == trace->trace_mem.da) { | ||
373 | already_added = true; | ||
374 | break; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | if (!already_added) | ||
379 | rproc_coredump_add_segment(rproc, trace->trace_mem.da, | ||
380 | trace->trace_mem.len); | ||
381 | } | ||
382 | } | ||
383 | |||
384 | static int stm32_rproc_start(struct rproc *rproc) | ||
385 | { | ||
386 | int err; | ||
387 | |||
388 | stm32_rproc_add_coredump_trace(rproc); | ||
389 | |||
390 | err = stm32_rproc_set_hold_boot(rproc, false); | ||
391 | if (err) | ||
392 | return err; | ||
393 | |||
394 | return stm32_rproc_set_hold_boot(rproc, true); | ||
395 | } | ||
396 | |||
397 | static int stm32_rproc_stop(struct rproc *rproc) | ||
398 | { | ||
399 | struct stm32_rproc *ddata = rproc->priv; | ||
400 | int err, dummy_data, idx; | ||
401 | |||
402 | /* request shutdown of the remote processor */ | ||
403 | if (rproc->state != RPROC_OFFLINE) { | ||
404 | idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_SHUTDOWN); | ||
405 | if (idx >= 0 && ddata->mb[idx].chan) { | ||
406 | /* a dummy data is sent to allow to block on transmit */ | ||
407 | err = mbox_send_message(ddata->mb[idx].chan, | ||
408 | &dummy_data); | ||
409 | if (err < 0) | ||
410 | dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n"); | ||
411 | } | ||
412 | } | ||
413 | |||
414 | err = stm32_rproc_set_hold_boot(rproc, true); | ||
415 | if (err) | ||
416 | return err; | ||
417 | |||
418 | err = reset_control_assert(ddata->rst); | ||
419 | if (err) { | ||
420 | dev_err(&rproc->dev, "failed to assert the reset\n"); | ||
421 | return err; | ||
422 | } | ||
423 | |||
424 | /* to allow platform Standby power mode, set remote proc Deep Sleep */ | ||
425 | if (ddata->pdds.map) { | ||
426 | err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg, | ||
427 | ddata->pdds.mask, 1); | ||
428 | if (err) { | ||
429 | dev_err(&rproc->dev, "failed to set pdds\n"); | ||
430 | return err; | ||
431 | } | ||
432 | } | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static void stm32_rproc_kick(struct rproc *rproc, int vqid) | ||
438 | { | ||
439 | struct stm32_rproc *ddata = rproc->priv; | ||
440 | unsigned int i; | ||
441 | int err; | ||
442 | |||
443 | if (WARN_ON(vqid >= MBOX_NB_VQ)) | ||
444 | return; | ||
445 | |||
446 | for (i = 0; i < MBOX_NB_MBX; i++) { | ||
447 | if (vqid != ddata->mb[i].vq_id) | ||
448 | continue; | ||
449 | if (!ddata->mb[i].chan) | ||
450 | return; | ||
451 | err = mbox_send_message(ddata->mb[i].chan, (void *)(long)vqid); | ||
452 | if (err < 0) | ||
453 | dev_err(&rproc->dev, "%s: failed (%s, err:%d)\n", | ||
454 | __func__, ddata->mb[i].name, err); | ||
455 | return; | ||
456 | } | ||
457 | } | ||
458 | |||
459 | static struct rproc_ops st_rproc_ops = { | ||
460 | .start = stm32_rproc_start, | ||
461 | .stop = stm32_rproc_stop, | ||
462 | .kick = stm32_rproc_kick, | ||
463 | .load = rproc_elf_load_segments, | ||
464 | .parse_fw = stm32_rproc_parse_fw, | ||
465 | .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, | ||
466 | .sanity_check = rproc_elf_sanity_check, | ||
467 | .get_boot_addr = rproc_elf_get_boot_addr, | ||
468 | }; | ||
469 | |||
470 | static const struct of_device_id stm32_rproc_match[] = { | ||
471 | { .compatible = "st,stm32mp1-m4" }, | ||
472 | {}, | ||
473 | }; | ||
474 | MODULE_DEVICE_TABLE(of, stm32_rproc_match); | ||
475 | |||
476 | static int stm32_rproc_get_syscon(struct device_node *np, const char *prop, | ||
477 | struct stm32_syscon *syscon) | ||
478 | { | ||
479 | int err = 0; | ||
480 | |||
481 | syscon->map = syscon_regmap_lookup_by_phandle(np, prop); | ||
482 | if (IS_ERR(syscon->map)) { | ||
483 | err = PTR_ERR(syscon->map); | ||
484 | syscon->map = NULL; | ||
485 | goto out; | ||
486 | } | ||
487 | |||
488 | err = of_property_read_u32_index(np, prop, 1, &syscon->reg); | ||
489 | if (err) | ||
490 | goto out; | ||
491 | |||
492 | err = of_property_read_u32_index(np, prop, 2, &syscon->mask); | ||
493 | |||
494 | out: | ||
495 | return err; | ||
496 | } | ||
497 | |||
498 | static int stm32_rproc_parse_dt(struct platform_device *pdev) | ||
499 | { | ||
500 | struct device *dev = &pdev->dev; | ||
501 | struct device_node *np = dev->of_node; | ||
502 | struct rproc *rproc = platform_get_drvdata(pdev); | ||
503 | struct stm32_rproc *ddata = rproc->priv; | ||
504 | struct stm32_syscon tz; | ||
505 | unsigned int tzen; | ||
506 | int err, irq; | ||
507 | |||
508 | irq = platform_get_irq(pdev, 0); | ||
509 | if (irq > 0) { | ||
510 | err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0, | ||
511 | dev_name(dev), rproc); | ||
512 | if (err) { | ||
513 | dev_err(dev, "failed to request wdg irq\n"); | ||
514 | return err; | ||
515 | } | ||
516 | |||
517 | dev_info(dev, "wdg irq registered\n"); | ||
518 | } | ||
519 | |||
520 | ddata->rst = devm_reset_control_get_by_index(dev, 0); | ||
521 | if (IS_ERR(ddata->rst)) { | ||
522 | dev_err(dev, "failed to get mcu reset\n"); | ||
523 | return PTR_ERR(ddata->rst); | ||
524 | } | ||
525 | |||
526 | /* | ||
527 | * if platform is secured the hold boot bit must be written by | ||
528 | * smc call and read normally. | ||
529 | * if not secure the hold boot bit could be read/write normally | ||
530 | */ | ||
531 | err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz); | ||
532 | if (err) { | ||
533 | dev_err(dev, "failed to get tz syscfg\n"); | ||
534 | return err; | ||
535 | } | ||
536 | |||
537 | err = regmap_read(tz.map, tz.reg, &tzen); | ||
538 | if (err) { | ||
539 | dev_err(&rproc->dev, "failed to read tzen\n"); | ||
540 | return err; | ||
541 | } | ||
542 | ddata->secured_soc = tzen & tz.mask; | ||
543 | |||
544 | err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot", | ||
545 | &ddata->hold_boot); | ||
546 | if (err) { | ||
547 | dev_err(dev, "failed to get hold boot\n"); | ||
548 | return err; | ||
549 | } | ||
550 | |||
551 | err = stm32_rproc_get_syscon(np, "st,syscfg-pdds", &ddata->pdds); | ||
552 | if (err) | ||
553 | dev_warn(dev, "failed to get pdds\n"); | ||
554 | |||
555 | rproc->auto_boot = of_property_read_bool(np, "st,auto-boot"); | ||
556 | |||
557 | return stm32_rproc_of_memory_translations(rproc); | ||
558 | } | ||
559 | |||
560 | static int stm32_rproc_probe(struct platform_device *pdev) | ||
561 | { | ||
562 | struct device *dev = &pdev->dev; | ||
563 | struct stm32_rproc *ddata; | ||
564 | struct device_node *np = dev->of_node; | ||
565 | struct rproc *rproc; | ||
566 | int ret; | ||
567 | |||
568 | ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); | ||
569 | if (ret) | ||
570 | return ret; | ||
571 | |||
572 | rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata)); | ||
573 | if (!rproc) | ||
574 | return -ENOMEM; | ||
575 | |||
576 | rproc->has_iommu = false; | ||
577 | ddata = rproc->priv; | ||
578 | |||
579 | platform_set_drvdata(pdev, rproc); | ||
580 | |||
581 | ret = stm32_rproc_parse_dt(pdev); | ||
582 | if (ret) | ||
583 | goto free_rproc; | ||
584 | |||
585 | stm32_rproc_request_mbox(rproc); | ||
586 | |||
587 | ret = rproc_add(rproc); | ||
588 | if (ret) | ||
589 | goto free_mb; | ||
590 | |||
591 | return 0; | ||
592 | |||
593 | free_mb: | ||
594 | stm32_rproc_free_mbox(rproc); | ||
595 | free_rproc: | ||
596 | rproc_free(rproc); | ||
597 | return ret; | ||
598 | } | ||
599 | |||
600 | static int stm32_rproc_remove(struct platform_device *pdev) | ||
601 | { | ||
602 | struct rproc *rproc = platform_get_drvdata(pdev); | ||
603 | |||
604 | if (atomic_read(&rproc->power) > 0) | ||
605 | rproc_shutdown(rproc); | ||
606 | |||
607 | rproc_del(rproc); | ||
608 | stm32_rproc_free_mbox(rproc); | ||
609 | rproc_free(rproc); | ||
610 | |||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | static struct platform_driver stm32_rproc_driver = { | ||
615 | .probe = stm32_rproc_probe, | ||
616 | .remove = stm32_rproc_remove, | ||
617 | .driver = { | ||
618 | .name = "stm32-rproc", | ||
619 | .of_match_table = of_match_ptr(stm32_rproc_match), | ||
620 | }, | ||
621 | }; | ||
622 | module_platform_driver(stm32_rproc_driver); | ||
623 | |||
624 | MODULE_DESCRIPTION("STM32 Remote Processor Control Driver"); | ||
625 | MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>"); | ||
626 | MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>"); | ||
627 | MODULE_LICENSE("GPL v2"); | ||
628 | |||