1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
8 #include <linux/interrupt.h>
9 #include <linux/kernel.h>
10 #include <linux/mfd/syscon.h>
11 #include <linux/module.h>
12 #include <linux/of_address.h>
13 #include <linux/of_device.h>
14 #include <linux/platform_device.h>
15 #include <linux/regmap.h>
16 #include <linux/remoteproc.h>
18 #define IMX7D_SRC_SCR 0x0C
19 #define IMX7D_ENABLE_M4 BIT(3)
20 #define IMX7D_SW_M4P_RST BIT(2)
21 #define IMX7D_SW_M4C_RST BIT(1)
22 #define IMX7D_SW_M4C_NON_SCLR_RST BIT(0)
24 #define IMX7D_M4_RST_MASK (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \
26 | IMX7D_SW_M4C_NON_SCLR_RST)
28 #define IMX7D_M4_START (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \
30 #define IMX7D_M4_STOP IMX7D_SW_M4C_NON_SCLR_RST
32 /* Address: 0x020D8000 */
33 #define IMX6SX_SRC_SCR 0x00
34 #define IMX6SX_ENABLE_M4 BIT(22)
35 #define IMX6SX_SW_M4P_RST BIT(12)
36 #define IMX6SX_SW_M4C_NON_SCLR_RST BIT(4)
37 #define IMX6SX_SW_M4C_RST BIT(3)
39 #define IMX6SX_M4_START (IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \
41 #define IMX6SX_M4_STOP IMX6SX_SW_M4C_NON_SCLR_RST
42 #define IMX6SX_M4_RST_MASK (IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \
43 | IMX6SX_SW_M4C_NON_SCLR_RST \
46 #define IMX7D_RPROC_MEM_MAX 8
49 * struct imx_rproc_mem - slim internal memory structure
50 * @cpu_addr: MPU virtual address of the memory region
51 * @sys_addr: Bus address used to access the memory region
52 * @size: Size of the memory region
54 struct imx_rproc_mem
{
55 void __iomem
*cpu_addr
;
61 /* M4 own area. Can be mapped at probe */
62 #define ATT_OWN BIT(1)
64 /* address translation table */
65 struct imx_rproc_att
{
66 u32 da
; /* device address (From Cortex M4 view)*/
67 u32 sa
; /* system bus address */
68 u32 size
; /* size of reg range */
72 struct imx_rproc_dcfg
{
77 const struct imx_rproc_att
*att
;
83 struct regmap
*regmap
;
85 const struct imx_rproc_dcfg
*dcfg
;
86 struct imx_rproc_mem mem
[IMX7D_RPROC_MEM_MAX
];
90 static const struct imx_rproc_att imx_rproc_att_imx7d
[] = {
91 /* dev addr , sys addr , size , flags */
92 /* OCRAM_S (M4 Boot code) - alias */
93 { 0x00000000, 0x00180000, 0x00008000, 0 },
95 { 0x00180000, 0x00180000, 0x00008000, ATT_OWN
},
96 /* OCRAM (Code) - alias */
97 { 0x00900000, 0x00900000, 0x00020000, 0 },
98 /* OCRAM_EPDC (Code) - alias */
99 { 0x00920000, 0x00920000, 0x00020000, 0 },
100 /* OCRAM_PXP (Code) - alias */
101 { 0x00940000, 0x00940000, 0x00008000, 0 },
103 { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN
},
104 /* DDR (Code) - alias, first part of DDR (Data) */
105 { 0x10000000, 0x80000000, 0x0FFF0000, 0 },
108 { 0x20000000, 0x00800000, 0x00008000, ATT_OWN
},
110 { 0x20200000, 0x00900000, 0x00020000, 0 },
111 /* OCRAM_EPDC (Data) */
112 { 0x20220000, 0x00920000, 0x00020000, 0 },
113 /* OCRAM_PXP (Data) */
114 { 0x20240000, 0x00940000, 0x00008000, 0 },
116 { 0x80000000, 0x80000000, 0x60000000, 0 },
119 static const struct imx_rproc_att imx_rproc_att_imx6sx
[] = {
120 /* dev addr , sys addr , size , flags */
121 /* TCML (M4 Boot Code) - alias */
122 { 0x00000000, 0x007F8000, 0x00008000, 0 },
124 { 0x00180000, 0x008F8000, 0x00004000, 0 },
125 /* OCRAM_S (Code) - alias */
126 { 0x00180000, 0x008FC000, 0x00004000, 0 },
128 { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN
},
129 /* DDR (Code) - alias, first part of DDR (Data) */
130 { 0x10000000, 0x80000000, 0x0FFF8000, 0 },
133 { 0x20000000, 0x00800000, 0x00008000, ATT_OWN
},
134 /* OCRAM_S (Data) - alias? */
135 { 0x208F8000, 0x008F8000, 0x00004000, 0 },
137 { 0x80000000, 0x80000000, 0x60000000, 0 },
140 static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d
= {
141 .src_reg
= IMX7D_SRC_SCR
,
142 .src_mask
= IMX7D_M4_RST_MASK
,
143 .src_start
= IMX7D_M4_START
,
144 .src_stop
= IMX7D_M4_STOP
,
145 .att
= imx_rproc_att_imx7d
,
146 .att_size
= ARRAY_SIZE(imx_rproc_att_imx7d
),
149 static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx
= {
150 .src_reg
= IMX6SX_SRC_SCR
,
151 .src_mask
= IMX6SX_M4_RST_MASK
,
152 .src_start
= IMX6SX_M4_START
,
153 .src_stop
= IMX6SX_M4_STOP
,
154 .att
= imx_rproc_att_imx6sx
,
155 .att_size
= ARRAY_SIZE(imx_rproc_att_imx6sx
),
158 static int imx_rproc_start(struct rproc
*rproc
)
160 struct imx_rproc
*priv
= rproc
->priv
;
161 const struct imx_rproc_dcfg
*dcfg
= priv
->dcfg
;
162 struct device
*dev
= priv
->dev
;
165 ret
= regmap_update_bits(priv
->regmap
, dcfg
->src_reg
,
166 dcfg
->src_mask
, dcfg
->src_start
);
168 dev_err(dev
, "Failed to enable M4!\n");
173 static int imx_rproc_stop(struct rproc
*rproc
)
175 struct imx_rproc
*priv
= rproc
->priv
;
176 const struct imx_rproc_dcfg
*dcfg
= priv
->dcfg
;
177 struct device
*dev
= priv
->dev
;
180 ret
= regmap_update_bits(priv
->regmap
, dcfg
->src_reg
,
181 dcfg
->src_mask
, dcfg
->src_stop
);
183 dev_err(dev
, "Failed to stop M4!\n");
188 static int imx_rproc_da_to_sys(struct imx_rproc
*priv
, u64 da
,
189 size_t len
, u64
*sys
)
191 const struct imx_rproc_dcfg
*dcfg
= priv
->dcfg
;
194 /* parse address translation table */
195 for (i
= 0; i
< dcfg
->att_size
; i
++) {
196 const struct imx_rproc_att
*att
= &dcfg
->att
[i
];
198 if (da
>= att
->da
&& da
+ len
< att
->da
+ att
->size
) {
199 unsigned int offset
= da
- att
->da
;
201 *sys
= att
->sa
+ offset
;
206 dev_warn(priv
->dev
, "Translation failed: da = 0x%llx len = 0x%zx\n",
211 static void *imx_rproc_da_to_va(struct rproc
*rproc
, u64 da
, size_t len
)
213 struct imx_rproc
*priv
= rproc
->priv
;
222 * On device side we have many aliases, so we need to convert device
223 * address (M4) to system bus address first.
225 if (imx_rproc_da_to_sys(priv
, da
, len
, &sys
))
228 for (i
= 0; i
< IMX7D_RPROC_MEM_MAX
; i
++) {
229 if (sys
>= priv
->mem
[i
].sys_addr
&& sys
+ len
<
230 priv
->mem
[i
].sys_addr
+ priv
->mem
[i
].size
) {
231 unsigned int offset
= sys
- priv
->mem
[i
].sys_addr
;
232 /* __force to make sparse happy with type conversion */
233 va
= (__force
void *)(priv
->mem
[i
].cpu_addr
+ offset
);
238 dev_dbg(&rproc
->dev
, "da = 0x%llx len = 0x%zx va = 0x%p\n",
244 static const struct rproc_ops imx_rproc_ops
= {
245 .start
= imx_rproc_start
,
246 .stop
= imx_rproc_stop
,
247 .da_to_va
= imx_rproc_da_to_va
,
250 static int imx_rproc_addr_init(struct imx_rproc
*priv
,
251 struct platform_device
*pdev
)
253 const struct imx_rproc_dcfg
*dcfg
= priv
->dcfg
;
254 struct device
*dev
= &pdev
->dev
;
255 struct device_node
*np
= dev
->of_node
;
256 int a
, b
= 0, err
, nph
;
258 /* remap required addresses */
259 for (a
= 0; a
< dcfg
->att_size
; a
++) {
260 const struct imx_rproc_att
*att
= &dcfg
->att
[a
];
262 if (!(att
->flags
& ATT_OWN
))
265 if (b
>= IMX7D_RPROC_MEM_MAX
)
268 priv
->mem
[b
].cpu_addr
= devm_ioremap(&pdev
->dev
,
270 if (!priv
->mem
[b
].cpu_addr
) {
271 dev_err(dev
, "devm_ioremap_resource failed\n");
274 priv
->mem
[b
].sys_addr
= att
->sa
;
275 priv
->mem
[b
].size
= att
->size
;
279 /* memory-region is optional property */
280 nph
= of_count_phandle_with_args(np
, "memory-region", NULL
);
284 /* remap optional addresses */
285 for (a
= 0; a
< nph
; a
++) {
286 struct device_node
*node
;
289 node
= of_parse_phandle(np
, "memory-region", a
);
290 err
= of_address_to_resource(node
, 0, &res
);
292 dev_err(dev
, "unable to resolve memory region\n");
296 if (b
>= IMX7D_RPROC_MEM_MAX
)
299 priv
->mem
[b
].cpu_addr
= devm_ioremap_resource(&pdev
->dev
, &res
);
300 if (IS_ERR(priv
->mem
[b
].cpu_addr
)) {
301 dev_err(dev
, "devm_ioremap_resource failed\n");
302 err
= PTR_ERR(priv
->mem
[b
].cpu_addr
);
305 priv
->mem
[b
].sys_addr
= res
.start
;
306 priv
->mem
[b
].size
= resource_size(&res
);
313 static int imx_rproc_probe(struct platform_device
*pdev
)
315 struct device
*dev
= &pdev
->dev
;
316 struct device_node
*np
= dev
->of_node
;
317 struct imx_rproc
*priv
;
319 struct regmap_config config
= { .name
= "imx-rproc" };
320 const struct imx_rproc_dcfg
*dcfg
;
321 struct regmap
*regmap
;
324 regmap
= syscon_regmap_lookup_by_phandle(np
, "syscon");
325 if (IS_ERR(regmap
)) {
326 dev_err(dev
, "failed to find syscon\n");
327 return PTR_ERR(regmap
);
329 regmap_attach_dev(dev
, regmap
, &config
);
331 /* set some other name then imx */
332 rproc
= rproc_alloc(dev
, "imx-rproc", &imx_rproc_ops
,
333 NULL
, sizeof(*priv
));
337 dcfg
= of_device_get_match_data(dev
);
345 priv
->regmap
= regmap
;
349 dev_set_drvdata(dev
, rproc
);
351 ret
= imx_rproc_addr_init(priv
, pdev
);
353 dev_err(dev
, "failed on imx_rproc_addr_init\n");
357 priv
->clk
= devm_clk_get(dev
, NULL
);
358 if (IS_ERR(priv
->clk
)) {
359 dev_err(dev
, "Failed to get clock\n");
360 ret
= PTR_ERR(priv
->clk
);
365 * clk for M4 block including memory. Should be
366 * enabled before .start for FW transfer.
368 ret
= clk_prepare_enable(priv
->clk
);
370 dev_err(&rproc
->dev
, "Failed to enable clock\n");
374 ret
= rproc_add(rproc
);
376 dev_err(dev
, "rproc_add failed\n");
383 clk_disable_unprepare(priv
->clk
);
390 static int imx_rproc_remove(struct platform_device
*pdev
)
392 struct rproc
*rproc
= platform_get_drvdata(pdev
);
393 struct imx_rproc
*priv
= rproc
->priv
;
395 clk_disable_unprepare(priv
->clk
);
402 static const struct of_device_id imx_rproc_of_match
[] = {
403 { .compatible
= "fsl,imx7d-cm4", .data
= &imx_rproc_cfg_imx7d
},
404 { .compatible
= "fsl,imx6sx-cm4", .data
= &imx_rproc_cfg_imx6sx
},
407 MODULE_DEVICE_TABLE(of
, imx_rproc_of_match
);
409 static struct platform_driver imx_rproc_driver
= {
410 .probe
= imx_rproc_probe
,
411 .remove
= imx_rproc_remove
,
414 .of_match_table
= imx_rproc_of_match
,
418 module_platform_driver(imx_rproc_driver
);
420 MODULE_LICENSE("GPL v2");
421 MODULE_DESCRIPTION("IMX6SX/7D remote processor control driver");
422 MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");