blob: d26254609a52e94bf8a74f809ecabf4bd5c85246 [file] [log] [blame]
Thomas Gleixnerd2912cb2019-06-04 10:11:33 +02001// SPDX-License-Identifier: GPL-2.0-only
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +02002/*
3 * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +02004 */
5
6#include <linux/clk.h>
7#include <linux/err.h>
8#include <linux/interrupt.h>
9#include <linux/kernel.h>
Peng Fan2df70622021-03-06 19:24:25 +080010#include <linux/mailbox_client.h>
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +020011#include <linux/mfd/syscon.h>
12#include <linux/module.h>
13#include <linux/of_address.h>
Peng Fanb29b4242021-03-06 19:24:22 +080014#include <linux/of_reserved_mem.h>
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +020015#include <linux/of_device.h>
16#include <linux/platform_device.h>
17#include <linux/regmap.h>
18#include <linux/remoteproc.h>
Peng Fan2df70622021-03-06 19:24:25 +080019#include <linux/workqueue.h>
20
21#include "remoteproc_internal.h"
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +020022
23#define IMX7D_SRC_SCR 0x0C
24#define IMX7D_ENABLE_M4 BIT(3)
25#define IMX7D_SW_M4P_RST BIT(2)
26#define IMX7D_SW_M4C_RST BIT(1)
27#define IMX7D_SW_M4C_NON_SCLR_RST BIT(0)
28
29#define IMX7D_M4_RST_MASK (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \
30 | IMX7D_SW_M4C_RST \
31 | IMX7D_SW_M4C_NON_SCLR_RST)
32
33#define IMX7D_M4_START (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \
34 | IMX7D_SW_M4C_RST)
35#define IMX7D_M4_STOP IMX7D_SW_M4C_NON_SCLR_RST
36
37/* Address: 0x020D8000 */
38#define IMX6SX_SRC_SCR 0x00
39#define IMX6SX_ENABLE_M4 BIT(22)
40#define IMX6SX_SW_M4P_RST BIT(12)
41#define IMX6SX_SW_M4C_NON_SCLR_RST BIT(4)
42#define IMX6SX_SW_M4C_RST BIT(3)
43
44#define IMX6SX_M4_START (IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \
45 | IMX6SX_SW_M4C_RST)
46#define IMX6SX_M4_STOP IMX6SX_SW_M4C_NON_SCLR_RST
47#define IMX6SX_M4_RST_MASK (IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \
48 | IMX6SX_SW_M4C_NON_SCLR_RST \
49 | IMX6SX_SW_M4C_RST)
50
Peng Fanf638a192021-04-08 09:44:47 +080051#define IMX_RPROC_MEM_MAX 32
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +020052
53/**
54 * struct imx_rproc_mem - slim internal memory structure
55 * @cpu_addr: MPU virtual address of the memory region
56 * @sys_addr: Bus address used to access the memory region
57 * @size: Size of the memory region
58 */
59struct imx_rproc_mem {
60 void __iomem *cpu_addr;
61 phys_addr_t sys_addr;
62 size_t size;
63};
64
65/* att flags */
66/* M4 own area. Can be mapped at probe */
67#define ATT_OWN BIT(1)
68
69/* address translation table */
70struct imx_rproc_att {
71 u32 da; /* device address (From Cortex M4 view)*/
72 u32 sa; /* system bus address */
73 u32 size; /* size of reg range */
74 int flags;
75};
76
Peng Fan52bda8d2021-05-06 12:08:40 +080077/* Remote core start/stop method */
78enum imx_rproc_method {
79 IMX_RPROC_NONE,
80 /* Through syscon regmap */
81 IMX_RPROC_MMIO,
82 /* Through ARM SMCCC */
83 IMX_RPROC_SMC,
84};
85
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +020086struct imx_rproc_dcfg {
87 u32 src_reg;
88 u32 src_mask;
89 u32 src_start;
90 u32 src_stop;
91 const struct imx_rproc_att *att;
92 size_t att_size;
Peng Fan52bda8d2021-05-06 12:08:40 +080093 enum imx_rproc_method method;
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +020094};
95
96struct imx_rproc {
97 struct device *dev;
98 struct regmap *regmap;
99 struct rproc *rproc;
100 const struct imx_rproc_dcfg *dcfg;
Peng Fanf638a192021-04-08 09:44:47 +0800101 struct imx_rproc_mem mem[IMX_RPROC_MEM_MAX];
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200102 struct clk *clk;
Peng Fan2df70622021-03-06 19:24:25 +0800103 struct mbox_client cl;
104 struct mbox_chan *tx_ch;
105 struct mbox_chan *rx_ch;
106 struct work_struct rproc_work;
107 struct workqueue_struct *workqueue;
Peng Fan5e4c1242021-04-08 09:44:49 +0800108 void __iomem *rsc_table;
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200109};
110
Peng Fan4ab8f962021-03-06 19:24:23 +0800111static const struct imx_rproc_att imx_rproc_att_imx8mq[] = {
112 /* dev addr , sys addr , size , flags */
113 /* TCML - alias */
114 { 0x00000000, 0x007e0000, 0x00020000, 0 },
115 /* OCRAM_S */
116 { 0x00180000, 0x00180000, 0x00008000, 0 },
117 /* OCRAM */
118 { 0x00900000, 0x00900000, 0x00020000, 0 },
119 /* OCRAM */
120 { 0x00920000, 0x00920000, 0x00020000, 0 },
121 /* QSPI Code - alias */
122 { 0x08000000, 0x08000000, 0x08000000, 0 },
123 /* DDR (Code) - alias */
124 { 0x10000000, 0x80000000, 0x0FFE0000, 0 },
125 /* TCML */
126 { 0x1FFE0000, 0x007E0000, 0x00020000, ATT_OWN },
127 /* TCMU */
128 { 0x20000000, 0x00800000, 0x00020000, ATT_OWN },
129 /* OCRAM_S */
130 { 0x20180000, 0x00180000, 0x00008000, ATT_OWN },
131 /* OCRAM */
132 { 0x20200000, 0x00900000, 0x00020000, ATT_OWN },
133 /* OCRAM */
134 { 0x20220000, 0x00920000, 0x00020000, ATT_OWN },
135 /* DDR (Data) */
136 { 0x40000000, 0x40000000, 0x80000000, 0 },
137};
138
Peng Fanc8a1a562021-05-06 12:08:42 +0800139static const struct imx_rproc_att imx_rproc_att_imx7ulp[] = {
140 {0x1FFD0000, 0x1FFD0000, 0x30000, ATT_OWN},
141 {0x20000000, 0x20000000, 0x10000, ATT_OWN},
142 {0x2F000000, 0x2F000000, 0x20000, ATT_OWN},
143 {0x2F020000, 0x2F020000, 0x20000, ATT_OWN},
144 {0x60000000, 0x60000000, 0x40000000, 0}
145};
146
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200147static const struct imx_rproc_att imx_rproc_att_imx7d[] = {
148 /* dev addr , sys addr , size , flags */
149 /* OCRAM_S (M4 Boot code) - alias */
150 { 0x00000000, 0x00180000, 0x00008000, 0 },
151 /* OCRAM_S (Code) */
152 { 0x00180000, 0x00180000, 0x00008000, ATT_OWN },
153 /* OCRAM (Code) - alias */
154 { 0x00900000, 0x00900000, 0x00020000, 0 },
155 /* OCRAM_EPDC (Code) - alias */
156 { 0x00920000, 0x00920000, 0x00020000, 0 },
157 /* OCRAM_PXP (Code) - alias */
158 { 0x00940000, 0x00940000, 0x00008000, 0 },
159 /* TCML (Code) */
160 { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN },
161 /* DDR (Code) - alias, first part of DDR (Data) */
162 { 0x10000000, 0x80000000, 0x0FFF0000, 0 },
163
164 /* TCMU (Data) */
165 { 0x20000000, 0x00800000, 0x00008000, ATT_OWN },
166 /* OCRAM (Data) */
167 { 0x20200000, 0x00900000, 0x00020000, 0 },
168 /* OCRAM_EPDC (Data) */
169 { 0x20220000, 0x00920000, 0x00020000, 0 },
170 /* OCRAM_PXP (Data) */
171 { 0x20240000, 0x00940000, 0x00008000, 0 },
172 /* DDR (Data) */
173 { 0x80000000, 0x80000000, 0x60000000, 0 },
174};
175
176static const struct imx_rproc_att imx_rproc_att_imx6sx[] = {
177 /* dev addr , sys addr , size , flags */
178 /* TCML (M4 Boot Code) - alias */
179 { 0x00000000, 0x007F8000, 0x00008000, 0 },
180 /* OCRAM_S (Code) */
181 { 0x00180000, 0x008F8000, 0x00004000, 0 },
182 /* OCRAM_S (Code) - alias */
183 { 0x00180000, 0x008FC000, 0x00004000, 0 },
184 /* TCML (Code) */
185 { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN },
186 /* DDR (Code) - alias, first part of DDR (Data) */
187 { 0x10000000, 0x80000000, 0x0FFF8000, 0 },
188
189 /* TCMU (Data) */
190 { 0x20000000, 0x00800000, 0x00008000, ATT_OWN },
191 /* OCRAM_S (Data) - alias? */
192 { 0x208F8000, 0x008F8000, 0x00004000, 0 },
193 /* DDR (Data) */
194 { 0x80000000, 0x80000000, 0x60000000, 0 },
195};
196
Peng Fan4ab8f962021-03-06 19:24:23 +0800197static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = {
198 .src_reg = IMX7D_SRC_SCR,
199 .src_mask = IMX7D_M4_RST_MASK,
200 .src_start = IMX7D_M4_START,
201 .src_stop = IMX7D_M4_STOP,
202 .att = imx_rproc_att_imx8mq,
203 .att_size = ARRAY_SIZE(imx_rproc_att_imx8mq),
Peng Fan52bda8d2021-05-06 12:08:40 +0800204 .method = IMX_RPROC_MMIO,
Peng Fan4ab8f962021-03-06 19:24:23 +0800205};
206
Peng Fanc8a1a562021-05-06 12:08:42 +0800207static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = {
208 .att = imx_rproc_att_imx7ulp,
209 .att_size = ARRAY_SIZE(imx_rproc_att_imx7ulp),
210 .method = IMX_RPROC_NONE,
211};
212
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200213static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = {
214 .src_reg = IMX7D_SRC_SCR,
215 .src_mask = IMX7D_M4_RST_MASK,
216 .src_start = IMX7D_M4_START,
217 .src_stop = IMX7D_M4_STOP,
218 .att = imx_rproc_att_imx7d,
219 .att_size = ARRAY_SIZE(imx_rproc_att_imx7d),
Peng Fan52bda8d2021-05-06 12:08:40 +0800220 .method = IMX_RPROC_MMIO,
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200221};
222
223static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = {
224 .src_reg = IMX6SX_SRC_SCR,
225 .src_mask = IMX6SX_M4_RST_MASK,
226 .src_start = IMX6SX_M4_START,
227 .src_stop = IMX6SX_M4_STOP,
228 .att = imx_rproc_att_imx6sx,
229 .att_size = ARRAY_SIZE(imx_rproc_att_imx6sx),
Peng Fan52bda8d2021-05-06 12:08:40 +0800230 .method = IMX_RPROC_MMIO,
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200231};
232
233static int imx_rproc_start(struct rproc *rproc)
234{
235 struct imx_rproc *priv = rproc->priv;
236 const struct imx_rproc_dcfg *dcfg = priv->dcfg;
237 struct device *dev = priv->dev;
238 int ret;
239
240 ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
241 dcfg->src_mask, dcfg->src_start);
242 if (ret)
Fabio Estevam16a3c632019-06-03 20:46:28 -0300243 dev_err(dev, "Failed to enable M4!\n");
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200244
245 return ret;
246}
247
248static int imx_rproc_stop(struct rproc *rproc)
249{
250 struct imx_rproc *priv = rproc->priv;
251 const struct imx_rproc_dcfg *dcfg = priv->dcfg;
252 struct device *dev = priv->dev;
253 int ret;
254
Peng Fanc8a1a562021-05-06 12:08:42 +0800255 if (dcfg->method == IMX_RPROC_NONE)
256 return -EOPNOTSUPP;
257
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200258 ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
259 dcfg->src_mask, dcfg->src_stop);
260 if (ret)
Fabio Estevam16a3c632019-06-03 20:46:28 -0300261 dev_err(dev, "Failed to stop M4!\n");
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200262
263 return ret;
264}
265
266static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
Clement Leger9ce3bf22020-03-02 10:38:55 +0100267 size_t len, u64 *sys)
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200268{
269 const struct imx_rproc_dcfg *dcfg = priv->dcfg;
270 int i;
271
272 /* parse address translation table */
273 for (i = 0; i < dcfg->att_size; i++) {
274 const struct imx_rproc_att *att = &dcfg->att[i];
275
276 if (da >= att->da && da + len < att->da + att->size) {
277 unsigned int offset = da - att->da;
278
279 *sys = att->sa + offset;
280 return 0;
281 }
282 }
283
Clement Leger9ce3bf22020-03-02 10:38:55 +0100284 dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%zx\n",
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200285 da, len);
286 return -ENOENT;
287}
288
Peng Fan40df0a92021-03-06 19:24:19 +0800289static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200290{
291 struct imx_rproc *priv = rproc->priv;
292 void *va = NULL;
293 u64 sys;
294 int i;
295
Clement Leger9ce3bf22020-03-02 10:38:55 +0100296 if (len == 0)
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200297 return NULL;
298
299 /*
300 * On device side we have many aliases, so we need to convert device
301 * address (M4) to system bus address first.
302 */
303 if (imx_rproc_da_to_sys(priv, da, len, &sys))
304 return NULL;
305
Peng Fanf638a192021-04-08 09:44:47 +0800306 for (i = 0; i < IMX_RPROC_MEM_MAX; i++) {
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200307 if (sys >= priv->mem[i].sys_addr && sys + len <
308 priv->mem[i].sys_addr + priv->mem[i].size) {
309 unsigned int offset = sys - priv->mem[i].sys_addr;
310 /* __force to make sparse happy with type conversion */
311 va = (__force void *)(priv->mem[i].cpu_addr + offset);
312 break;
313 }
314 }
315
Clement Leger9ce3bf22020-03-02 10:38:55 +0100316 dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%zx va = 0x%p\n",
317 da, len, va);
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200318
319 return va;
320}
321
Peng Fanb29b4242021-03-06 19:24:22 +0800322static int imx_rproc_mem_alloc(struct rproc *rproc,
323 struct rproc_mem_entry *mem)
324{
325 struct device *dev = rproc->dev.parent;
326 void *va;
327
328 dev_dbg(dev, "map memory: %p+%zx\n", &mem->dma, mem->len);
329 va = ioremap_wc(mem->dma, mem->len);
330 if (IS_ERR_OR_NULL(va)) {
331 dev_err(dev, "Unable to map memory region: %p+%zx\n",
332 &mem->dma, mem->len);
333 return -ENOMEM;
334 }
335
336 /* Update memory entry va */
337 mem->va = va;
338
339 return 0;
340}
341
342static int imx_rproc_mem_release(struct rproc *rproc,
343 struct rproc_mem_entry *mem)
344{
345 dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma);
346 iounmap(mem->va);
347
348 return 0;
349}
350
Peng Fan10a3d402021-04-08 09:44:48 +0800351static int imx_rproc_prepare(struct rproc *rproc)
Peng Fanb29b4242021-03-06 19:24:22 +0800352{
353 struct imx_rproc *priv = rproc->priv;
354 struct device_node *np = priv->dev->of_node;
355 struct of_phandle_iterator it;
356 struct rproc_mem_entry *mem;
357 struct reserved_mem *rmem;
358 u32 da;
359
360 /* Register associated reserved memory regions */
361 of_phandle_iterator_init(&it, np, "memory-region", NULL, 0);
362 while (of_phandle_iterator_next(&it) == 0) {
363 /*
364 * Ignore the first memory region which will be used vdev buffer.
365 * No need to do extra handlings, rproc_add_virtio_dev will handle it.
366 */
367 if (!strcmp(it.node->name, "vdev0buffer"))
368 continue;
369
370 rmem = of_reserved_mem_lookup(it.node);
371 if (!rmem) {
372 dev_err(priv->dev, "unable to acquire memory-region\n");
373 return -EINVAL;
374 }
375
376 /* No need to translate pa to da, i.MX use same map */
377 da = rmem->base;
378
379 /* Register memory region */
380 mem = rproc_mem_entry_init(priv->dev, NULL, (dma_addr_t)rmem->base, rmem->size, da,
381 imx_rproc_mem_alloc, imx_rproc_mem_release,
382 it.node->name);
383
384 if (mem)
385 rproc_coredump_add_segment(rproc, da, rmem->size);
386 else
387 return -ENOMEM;
388
389 rproc_add_carveout(rproc, mem);
390 }
391
392 return 0;
393}
394
395static int imx_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
396{
Peng Fan10a3d402021-04-08 09:44:48 +0800397 int ret;
Peng Fanb29b4242021-03-06 19:24:22 +0800398
399 ret = rproc_elf_load_rsc_table(rproc, fw);
400 if (ret)
401 dev_info(&rproc->dev, "No resource table in elf\n");
402
403 return 0;
404}
405
Peng Fan2df70622021-03-06 19:24:25 +0800406static void imx_rproc_kick(struct rproc *rproc, int vqid)
407{
408 struct imx_rproc *priv = rproc->priv;
409 int err;
410 __u32 mmsg;
411
412 if (!priv->tx_ch) {
413 dev_err(priv->dev, "No initialized mbox tx channel\n");
414 return;
415 }
416
417 /*
418 * Send the index of the triggered virtqueue as the mu payload.
419 * Let remote processor know which virtqueue is used.
420 */
421 mmsg = vqid << 16;
422
423 err = mbox_send_message(priv->tx_ch, (void *)&mmsg);
424 if (err < 0)
425 dev_err(priv->dev, "%s: failed (%d, err:%d)\n",
426 __func__, vqid, err);
427}
428
Peng Fan5e4c1242021-04-08 09:44:49 +0800429static int imx_rproc_attach(struct rproc *rproc)
430{
431 return 0;
432}
433
434static struct resource_table *imx_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
435{
436 struct imx_rproc *priv = rproc->priv;
437
438 /* The resource table has already been mapped in imx_rproc_addr_init */
439 if (!priv->rsc_table)
440 return NULL;
441
442 *table_sz = SZ_1K;
443 return (struct resource_table *)priv->rsc_table;
444}
445
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200446static const struct rproc_ops imx_rproc_ops = {
Peng Fan10a3d402021-04-08 09:44:48 +0800447 .prepare = imx_rproc_prepare,
Peng Fan5e4c1242021-04-08 09:44:49 +0800448 .attach = imx_rproc_attach,
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200449 .start = imx_rproc_start,
450 .stop = imx_rproc_stop,
Peng Fan2df70622021-03-06 19:24:25 +0800451 .kick = imx_rproc_kick,
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200452 .da_to_va = imx_rproc_da_to_va,
Peng Fanb29b4242021-03-06 19:24:22 +0800453 .load = rproc_elf_load_segments,
454 .parse_fw = imx_rproc_parse_fw,
455 .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
Peng Fan5e4c1242021-04-08 09:44:49 +0800456 .get_loaded_rsc_table = imx_rproc_get_loaded_rsc_table,
Peng Fanb29b4242021-03-06 19:24:22 +0800457 .sanity_check = rproc_elf_sanity_check,
458 .get_boot_addr = rproc_elf_get_boot_addr,
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200459};
460
461static int imx_rproc_addr_init(struct imx_rproc *priv,
462 struct platform_device *pdev)
463{
464 const struct imx_rproc_dcfg *dcfg = priv->dcfg;
465 struct device *dev = &pdev->dev;
466 struct device_node *np = dev->of_node;
467 int a, b = 0, err, nph;
468
469 /* remap required addresses */
470 for (a = 0; a < dcfg->att_size; a++) {
471 const struct imx_rproc_att *att = &dcfg->att[a];
472
473 if (!(att->flags & ATT_OWN))
474 continue;
475
Peng Fanf638a192021-04-08 09:44:47 +0800476 if (b >= IMX_RPROC_MEM_MAX)
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200477 break;
478
479 priv->mem[b].cpu_addr = devm_ioremap(&pdev->dev,
480 att->sa, att->size);
Wei Yongjun68a39a32017-10-11 10:48:44 +0000481 if (!priv->mem[b].cpu_addr) {
Peng Fan1896b3d2021-03-06 19:24:20 +0800482 dev_err(dev, "failed to remap %#x bytes from %#x\n", att->size, att->sa);
Wei Yongjun68a39a32017-10-11 10:48:44 +0000483 return -ENOMEM;
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200484 }
485 priv->mem[b].sys_addr = att->sa;
486 priv->mem[b].size = att->size;
487 b++;
488 }
489
490 /* memory-region is optional property */
491 nph = of_count_phandle_with_args(np, "memory-region", NULL);
492 if (nph <= 0)
493 return 0;
494
495 /* remap optional addresses */
496 for (a = 0; a < nph; a++) {
497 struct device_node *node;
498 struct resource res;
499
500 node = of_parse_phandle(np, "memory-region", a);
Peng Fan8f2d8962021-03-06 19:24:24 +0800501 /* Not map vdev region */
502 if (!strcmp(node->name, "vdev"))
503 continue;
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200504 err = of_address_to_resource(node, 0, &res);
505 if (err) {
506 dev_err(dev, "unable to resolve memory region\n");
507 return err;
508 }
509
Peng Fan6e962bf2021-04-08 09:44:46 +0800510 of_node_put(node);
511
Peng Fanf638a192021-04-08 09:44:47 +0800512 if (b >= IMX_RPROC_MEM_MAX)
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200513 break;
514
Peng Fanecadcc42021-03-06 19:24:21 +0800515 /* Not use resource version, because we might share region */
516 priv->mem[b].cpu_addr = devm_ioremap(&pdev->dev, res.start, resource_size(&res));
Wei Yongjun18cda802021-03-12 08:04:20 +0000517 if (!priv->mem[b].cpu_addr) {
Peng Fan1896b3d2021-03-06 19:24:20 +0800518 dev_err(dev, "failed to remap %pr\n", &res);
Wei Yongjun18cda802021-03-12 08:04:20 +0000519 return -ENOMEM;
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200520 }
521 priv->mem[b].sys_addr = res.start;
522 priv->mem[b].size = resource_size(&res);
Peng Fan5e4c1242021-04-08 09:44:49 +0800523 if (!strcmp(node->name, "rsc_table"))
524 priv->rsc_table = priv->mem[b].cpu_addr;
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200525 b++;
526 }
527
528 return 0;
529}
530
Peng Fan2df70622021-03-06 19:24:25 +0800531static void imx_rproc_vq_work(struct work_struct *work)
532{
533 struct imx_rproc *priv = container_of(work, struct imx_rproc,
534 rproc_work);
535
536 rproc_vq_interrupt(priv->rproc, 0);
537 rproc_vq_interrupt(priv->rproc, 1);
538}
539
540static void imx_rproc_rx_callback(struct mbox_client *cl, void *msg)
541{
542 struct rproc *rproc = dev_get_drvdata(cl->dev);
543 struct imx_rproc *priv = rproc->priv;
544
545 queue_work(priv->workqueue, &priv->rproc_work);
546}
547
548static int imx_rproc_xtr_mbox_init(struct rproc *rproc)
549{
550 struct imx_rproc *priv = rproc->priv;
551 struct device *dev = priv->dev;
552 struct mbox_client *cl;
553 int ret;
554
555 if (!of_get_property(dev->of_node, "mbox-names", NULL))
556 return 0;
557
558 cl = &priv->cl;
559 cl->dev = dev;
560 cl->tx_block = true;
561 cl->tx_tout = 100;
562 cl->knows_txdone = false;
563 cl->rx_callback = imx_rproc_rx_callback;
564
565 priv->tx_ch = mbox_request_channel_byname(cl, "tx");
566 if (IS_ERR(priv->tx_ch)) {
567 ret = PTR_ERR(priv->tx_ch);
568 return dev_err_probe(cl->dev, ret,
569 "failed to request tx mailbox channel: %d\n", ret);
570 }
571
572 priv->rx_ch = mbox_request_channel_byname(cl, "rx");
573 if (IS_ERR(priv->rx_ch)) {
574 mbox_free_channel(priv->tx_ch);
575 ret = PTR_ERR(priv->rx_ch);
576 return dev_err_probe(cl->dev, ret,
577 "failed to request rx mailbox channel: %d\n", ret);
578 }
579
580 return 0;
581}
582
583static void imx_rproc_free_mbox(struct rproc *rproc)
584{
585 struct imx_rproc *priv = rproc->priv;
586
587 mbox_free_channel(priv->tx_ch);
588 mbox_free_channel(priv->rx_ch);
589}
590
Peng Fan5e4c1242021-04-08 09:44:49 +0800591static int imx_rproc_detect_mode(struct imx_rproc *priv)
592{
Peng Fanc8a1a562021-05-06 12:08:42 +0800593 struct regmap_config config = { .name = "imx-rproc" };
Peng Fan5e4c1242021-04-08 09:44:49 +0800594 const struct imx_rproc_dcfg *dcfg = priv->dcfg;
595 struct device *dev = priv->dev;
Peng Fanc8a1a562021-05-06 12:08:42 +0800596 struct regmap *regmap;
Peng Fan5e4c1242021-04-08 09:44:49 +0800597 int ret;
598 u32 val;
599
Peng Fanc8a1a562021-05-06 12:08:42 +0800600 switch (dcfg->method) {
601 case IMX_RPROC_NONE:
602 priv->rproc->state = RPROC_DETACHED;
603 return 0;
604 default:
605 break;
606 }
607
608 regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
609 if (IS_ERR(regmap)) {
610 dev_err(dev, "failed to find syscon\n");
611 return PTR_ERR(regmap);
612 }
613
614 priv->regmap = regmap;
615 regmap_attach_dev(dev, regmap, &config);
616
617 ret = regmap_read(regmap, dcfg->src_reg, &val);
Peng Fan5e4c1242021-04-08 09:44:49 +0800618 if (ret) {
619 dev_err(dev, "Failed to read src\n");
620 return ret;
621 }
622
623 if (!(val & dcfg->src_stop))
624 priv->rproc->state = RPROC_DETACHED;
625
626 return 0;
627}
628
Peng Fancc0316c2021-05-06 12:08:41 +0800629static int imx_rproc_clk_enable(struct imx_rproc *priv)
630{
631 const struct imx_rproc_dcfg *dcfg = priv->dcfg;
632 struct device *dev = priv->dev;
633 int ret;
634
635 /* Remote core is not under control of Linux */
636 if (dcfg->method == IMX_RPROC_NONE)
637 return 0;
638
639 priv->clk = devm_clk_get(dev, NULL);
640 if (IS_ERR(priv->clk)) {
641 dev_err(dev, "Failed to get clock\n");
642 return PTR_ERR(priv->clk);
643 }
644
645 /*
646 * clk for M4 block including memory. Should be
647 * enabled before .start for FW transfer.
648 */
649 ret = clk_prepare_enable(priv->clk);
650 if (ret) {
651 dev_err(dev, "Failed to enable clock\n");
652 return ret;
653 }
654
655 return 0;
656}
657
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200658static int imx_rproc_probe(struct platform_device *pdev)
659{
660 struct device *dev = &pdev->dev;
661 struct device_node *np = dev->of_node;
662 struct imx_rproc *priv;
663 struct rproc *rproc;
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200664 const struct imx_rproc_dcfg *dcfg;
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200665 int ret;
666
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200667 /* set some other name then imx */
668 rproc = rproc_alloc(dev, "imx-rproc", &imx_rproc_ops,
669 NULL, sizeof(*priv));
Christophe JAILLET99a31ad2018-03-14 20:56:39 +0100670 if (!rproc)
671 return -ENOMEM;
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200672
673 dcfg = of_device_get_match_data(dev);
Christophe JAILLETde6f83f2018-03-14 20:56:37 +0100674 if (!dcfg) {
675 ret = -EINVAL;
676 goto err_put_rproc;
677 }
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200678
679 priv = rproc->priv;
680 priv->rproc = rproc;
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200681 priv->dcfg = dcfg;
682 priv->dev = dev;
683
684 dev_set_drvdata(dev, rproc);
Peng Fan2df70622021-03-06 19:24:25 +0800685 priv->workqueue = create_workqueue(dev_name(dev));
686 if (!priv->workqueue) {
687 dev_err(dev, "cannot create workqueue\n");
688 ret = -ENOMEM;
689 goto err_put_rproc;
690 }
691
692 ret = imx_rproc_xtr_mbox_init(rproc);
693 if (ret)
694 goto err_put_wkq;
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200695
696 ret = imx_rproc_addr_init(priv, pdev);
697 if (ret) {
Fabio Estevam16a3c632019-06-03 20:46:28 -0300698 dev_err(dev, "failed on imx_rproc_addr_init\n");
Peng Fan2df70622021-03-06 19:24:25 +0800699 goto err_put_mbox;
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200700 }
701
Peng Fan5e4c1242021-04-08 09:44:49 +0800702 ret = imx_rproc_detect_mode(priv);
703 if (ret)
704 goto err_put_mbox;
705
Peng Fancc0316c2021-05-06 12:08:41 +0800706 ret = imx_rproc_clk_enable(priv);
707 if (ret)
Peng Fan2df70622021-03-06 19:24:25 +0800708 goto err_put_mbox;
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200709
Peng Fan2df70622021-03-06 19:24:25 +0800710 INIT_WORK(&priv->rproc_work, imx_rproc_vq_work);
711
Peng Fane13d1a42021-05-06 12:08:39 +0800712 if (rproc->state != RPROC_DETACHED)
713 rproc->auto_boot = of_property_read_bool(np, "fsl,auto-boot");
714
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200715 ret = rproc_add(rproc);
716 if (ret) {
717 dev_err(dev, "rproc_add failed\n");
718 goto err_put_clk;
719 }
720
Christophe JAILLET99a31ad2018-03-14 20:56:39 +0100721 return 0;
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200722
723err_put_clk:
724 clk_disable_unprepare(priv->clk);
Peng Fan2df70622021-03-06 19:24:25 +0800725err_put_mbox:
726 imx_rproc_free_mbox(rproc);
727err_put_wkq:
728 destroy_workqueue(priv->workqueue);
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200729err_put_rproc:
730 rproc_free(rproc);
Christophe JAILLET99a31ad2018-03-14 20:56:39 +0100731
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200732 return ret;
733}
734
735static int imx_rproc_remove(struct platform_device *pdev)
736{
737 struct rproc *rproc = platform_get_drvdata(pdev);
738 struct imx_rproc *priv = rproc->priv;
739
740 clk_disable_unprepare(priv->clk);
741 rproc_del(rproc);
Peng Fan2df70622021-03-06 19:24:25 +0800742 imx_rproc_free_mbox(rproc);
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200743 rproc_free(rproc);
744
745 return 0;
746}
747
748static const struct of_device_id imx_rproc_of_match[] = {
Peng Fanc8a1a562021-05-06 12:08:42 +0800749 { .compatible = "fsl,imx7ulp-cm4", .data = &imx_rproc_cfg_imx7ulp },
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200750 { .compatible = "fsl,imx7d-cm4", .data = &imx_rproc_cfg_imx7d },
751 { .compatible = "fsl,imx6sx-cm4", .data = &imx_rproc_cfg_imx6sx },
Peng Fan4ab8f962021-03-06 19:24:23 +0800752 { .compatible = "fsl,imx8mq-cm4", .data = &imx_rproc_cfg_imx8mq },
753 { .compatible = "fsl,imx8mm-cm4", .data = &imx_rproc_cfg_imx8mq },
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200754 {},
755};
756MODULE_DEVICE_TABLE(of, imx_rproc_of_match);
757
758static struct platform_driver imx_rproc_driver = {
759 .probe = imx_rproc_probe,
760 .remove = imx_rproc_remove,
761 .driver = {
762 .name = "imx-rproc",
763 .of_match_table = imx_rproc_of_match,
764 },
765};
766
767module_platform_driver(imx_rproc_driver);
768
769MODULE_LICENSE("GPL v2");
Peng Fan4ab8f962021-03-06 19:24:23 +0800770MODULE_DESCRIPTION("i.MX remote processor control driver");
Oleksij Rempela0ff4aa62017-08-17 09:15:26 +0200771MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");