2 * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation.
10 #include <linux/err.h>
11 #include <linux/interrupt.h>
12 #include <linux/kernel.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/platform_device.h>
18 #include <linux/regmap.h>
19 #include <linux/remoteproc.h>
21 #define IMX7D_SRC_SCR 0x0C
22 #define IMX7D_ENABLE_M4 BIT(3)
23 #define IMX7D_SW_M4P_RST BIT(2)
24 #define IMX7D_SW_M4C_RST BIT(1)
25 #define IMX7D_SW_M4C_NON_SCLR_RST BIT(0)
27 #define IMX7D_M4_RST_MASK (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \
29 | IMX7D_SW_M4C_NON_SCLR_RST)
31 #define IMX7D_M4_START (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \
33 #define IMX7D_M4_STOP IMX7D_SW_M4C_NON_SCLR_RST
35 /* Address: 0x020D8000 */
36 #define IMX6SX_SRC_SCR 0x00
37 #define IMX6SX_ENABLE_M4 BIT(22)
38 #define IMX6SX_SW_M4P_RST BIT(12)
39 #define IMX6SX_SW_M4C_NON_SCLR_RST BIT(4)
40 #define IMX6SX_SW_M4C_RST BIT(3)
42 #define IMX6SX_M4_START (IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \
44 #define IMX6SX_M4_STOP IMX6SX_SW_M4C_NON_SCLR_RST
45 #define IMX6SX_M4_RST_MASK (IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \
46 | IMX6SX_SW_M4C_NON_SCLR_RST \
49 #define IMX7D_RPROC_MEM_MAX 8
52 * struct imx_rproc_mem - slim internal memory structure
53 * @cpu_addr: MPU virtual address of the memory region
54 * @sys_addr: Bus address used to access the memory region
55 * @size: Size of the memory region
57 struct imx_rproc_mem
{
58 void __iomem
*cpu_addr
;
64 /* M4 own area. Can be mapped at probe */
65 #define ATT_OWN BIT(1)
67 /* address translation table */
68 struct imx_rproc_att
{
69 u32 da
; /* device address (From Cortex M4 view)*/
70 u32 sa
; /* system bus address */
71 u32 size
; /* size of reg range */
75 struct imx_rproc_dcfg
{
80 const struct imx_rproc_att
*att
;
86 struct regmap
*regmap
;
88 const struct imx_rproc_dcfg
*dcfg
;
89 struct imx_rproc_mem mem
[IMX7D_RPROC_MEM_MAX
];
93 static const struct imx_rproc_att imx_rproc_att_imx7d
[] = {
94 /* dev addr , sys addr , size , flags */
95 /* OCRAM_S (M4 Boot code) - alias */
96 { 0x00000000, 0x00180000, 0x00008000, 0 },
98 { 0x00180000, 0x00180000, 0x00008000, ATT_OWN
},
99 /* OCRAM (Code) - alias */
100 { 0x00900000, 0x00900000, 0x00020000, 0 },
101 /* OCRAM_EPDC (Code) - alias */
102 { 0x00920000, 0x00920000, 0x00020000, 0 },
103 /* OCRAM_PXP (Code) - alias */
104 { 0x00940000, 0x00940000, 0x00008000, 0 },
106 { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN
},
107 /* DDR (Code) - alias, first part of DDR (Data) */
108 { 0x10000000, 0x80000000, 0x0FFF0000, 0 },
111 { 0x20000000, 0x00800000, 0x00008000, ATT_OWN
},
113 { 0x20200000, 0x00900000, 0x00020000, 0 },
114 /* OCRAM_EPDC (Data) */
115 { 0x20220000, 0x00920000, 0x00020000, 0 },
116 /* OCRAM_PXP (Data) */
117 { 0x20240000, 0x00940000, 0x00008000, 0 },
119 { 0x80000000, 0x80000000, 0x60000000, 0 },
122 static const struct imx_rproc_att imx_rproc_att_imx6sx
[] = {
123 /* dev addr , sys addr , size , flags */
124 /* TCML (M4 Boot Code) - alias */
125 { 0x00000000, 0x007F8000, 0x00008000, 0 },
127 { 0x00180000, 0x008F8000, 0x00004000, 0 },
128 /* OCRAM_S (Code) - alias */
129 { 0x00180000, 0x008FC000, 0x00004000, 0 },
131 { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN
},
132 /* DDR (Code) - alias, first part of DDR (Data) */
133 { 0x10000000, 0x80000000, 0x0FFF8000, 0 },
136 { 0x20000000, 0x00800000, 0x00008000, ATT_OWN
},
137 /* OCRAM_S (Data) - alias? */
138 { 0x208F8000, 0x008F8000, 0x00004000, 0 },
140 { 0x80000000, 0x80000000, 0x60000000, 0 },
143 static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d
= {
144 .src_reg
= IMX7D_SRC_SCR
,
145 .src_mask
= IMX7D_M4_RST_MASK
,
146 .src_start
= IMX7D_M4_START
,
147 .src_stop
= IMX7D_M4_STOP
,
148 .att
= imx_rproc_att_imx7d
,
149 .att_size
= ARRAY_SIZE(imx_rproc_att_imx7d
),
152 static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx
= {
153 .src_reg
= IMX6SX_SRC_SCR
,
154 .src_mask
= IMX6SX_M4_RST_MASK
,
155 .src_start
= IMX6SX_M4_START
,
156 .src_stop
= IMX6SX_M4_STOP
,
157 .att
= imx_rproc_att_imx6sx
,
158 .att_size
= ARRAY_SIZE(imx_rproc_att_imx6sx
),
161 static int imx_rproc_start(struct rproc
*rproc
)
163 struct imx_rproc
*priv
= rproc
->priv
;
164 const struct imx_rproc_dcfg
*dcfg
= priv
->dcfg
;
165 struct device
*dev
= priv
->dev
;
168 ret
= regmap_update_bits(priv
->regmap
, dcfg
->src_reg
,
169 dcfg
->src_mask
, dcfg
->src_start
);
171 dev_err(dev
, "Filed to enable M4!\n");
176 static int imx_rproc_stop(struct rproc
*rproc
)
178 struct imx_rproc
*priv
= rproc
->priv
;
179 const struct imx_rproc_dcfg
*dcfg
= priv
->dcfg
;
180 struct device
*dev
= priv
->dev
;
183 ret
= regmap_update_bits(priv
->regmap
, dcfg
->src_reg
,
184 dcfg
->src_mask
, dcfg
->src_stop
);
186 dev_err(dev
, "Filed to stop M4!\n");
191 static int imx_rproc_da_to_sys(struct imx_rproc
*priv
, u64 da
,
194 const struct imx_rproc_dcfg
*dcfg
= priv
->dcfg
;
197 /* parse address translation table */
198 for (i
= 0; i
< dcfg
->att_size
; i
++) {
199 const struct imx_rproc_att
*att
= &dcfg
->att
[i
];
201 if (da
>= att
->da
&& da
+ len
< att
->da
+ att
->size
) {
202 unsigned int offset
= da
- att
->da
;
204 *sys
= att
->sa
+ offset
;
209 dev_warn(priv
->dev
, "Translation filed: da = 0x%llx len = 0x%x\n",
214 static void *imx_rproc_da_to_va(struct rproc
*rproc
, u64 da
, int len
)
216 struct imx_rproc
*priv
= rproc
->priv
;
225 * On device side we have many aliases, so we need to convert device
226 * address (M4) to system bus address first.
228 if (imx_rproc_da_to_sys(priv
, da
, len
, &sys
))
231 for (i
= 0; i
< IMX7D_RPROC_MEM_MAX
; i
++) {
232 if (sys
>= priv
->mem
[i
].sys_addr
&& sys
+ len
<
233 priv
->mem
[i
].sys_addr
+ priv
->mem
[i
].size
) {
234 unsigned int offset
= sys
- priv
->mem
[i
].sys_addr
;
235 /* __force to make sparse happy with type conversion */
236 va
= (__force
void *)(priv
->mem
[i
].cpu_addr
+ offset
);
241 dev_dbg(&rproc
->dev
, "da = 0x%llx len = 0x%x va = 0x%p\n", da
, len
, va
);
246 static const struct rproc_ops imx_rproc_ops
= {
247 .start
= imx_rproc_start
,
248 .stop
= imx_rproc_stop
,
249 .da_to_va
= imx_rproc_da_to_va
,
252 static int imx_rproc_addr_init(struct imx_rproc
*priv
,
253 struct platform_device
*pdev
)
255 const struct imx_rproc_dcfg
*dcfg
= priv
->dcfg
;
256 struct device
*dev
= &pdev
->dev
;
257 struct device_node
*np
= dev
->of_node
;
258 int a
, b
= 0, err
, nph
;
260 /* remap required addresses */
261 for (a
= 0; a
< dcfg
->att_size
; a
++) {
262 const struct imx_rproc_att
*att
= &dcfg
->att
[a
];
264 if (!(att
->flags
& ATT_OWN
))
267 if (b
>= IMX7D_RPROC_MEM_MAX
)
270 priv
->mem
[b
].cpu_addr
= devm_ioremap(&pdev
->dev
,
272 if (!priv
->mem
[b
].cpu_addr
) {
273 dev_err(dev
, "devm_ioremap_resource failed\n");
276 priv
->mem
[b
].sys_addr
= att
->sa
;
277 priv
->mem
[b
].size
= att
->size
;
281 /* memory-region is optional property */
282 nph
= of_count_phandle_with_args(np
, "memory-region", NULL
);
286 /* remap optional addresses */
287 for (a
= 0; a
< nph
; a
++) {
288 struct device_node
*node
;
291 node
= of_parse_phandle(np
, "memory-region", a
);
292 err
= of_address_to_resource(node
, 0, &res
);
294 dev_err(dev
, "unable to resolve memory region\n");
298 if (b
>= IMX7D_RPROC_MEM_MAX
)
301 priv
->mem
[b
].cpu_addr
= devm_ioremap_resource(&pdev
->dev
, &res
);
302 if (IS_ERR(priv
->mem
[b
].cpu_addr
)) {
303 dev_err(dev
, "devm_ioremap_resource failed\n");
304 err
= PTR_ERR(priv
->mem
[b
].cpu_addr
);
307 priv
->mem
[b
].sys_addr
= res
.start
;
308 priv
->mem
[b
].size
= resource_size(&res
);
315 static int imx_rproc_probe(struct platform_device
*pdev
)
317 struct device
*dev
= &pdev
->dev
;
318 struct device_node
*np
= dev
->of_node
;
319 struct imx_rproc
*priv
;
321 struct regmap_config config
= { .name
= "imx-rproc" };
322 const struct imx_rproc_dcfg
*dcfg
;
323 struct regmap
*regmap
;
326 regmap
= syscon_regmap_lookup_by_phandle(np
, "syscon");
327 if (IS_ERR(regmap
)) {
328 dev_err(dev
, "failed to find syscon\n");
329 return PTR_ERR(regmap
);
331 regmap_attach_dev(dev
, regmap
, &config
);
333 /* set some other name then imx */
334 rproc
= rproc_alloc(dev
, "imx-rproc", &imx_rproc_ops
,
335 NULL
, sizeof(*priv
));
339 dcfg
= of_device_get_match_data(dev
);
347 priv
->regmap
= regmap
;
351 dev_set_drvdata(dev
, rproc
);
353 ret
= imx_rproc_addr_init(priv
, pdev
);
355 dev_err(dev
, "filed on imx_rproc_addr_init\n");
359 priv
->clk
= devm_clk_get(dev
, NULL
);
360 if (IS_ERR(priv
->clk
)) {
361 dev_err(dev
, "Failed to get clock\n");
362 ret
= PTR_ERR(priv
->clk
);
367 * clk for M4 block including memory. Should be
368 * enabled before .start for FW transfer.
370 ret
= clk_prepare_enable(priv
->clk
);
372 dev_err(&rproc
->dev
, "Failed to enable clock\n");
376 ret
= rproc_add(rproc
);
378 dev_err(dev
, "rproc_add failed\n");
385 clk_disable_unprepare(priv
->clk
);
392 static int imx_rproc_remove(struct platform_device
*pdev
)
394 struct rproc
*rproc
= platform_get_drvdata(pdev
);
395 struct imx_rproc
*priv
= rproc
->priv
;
397 clk_disable_unprepare(priv
->clk
);
404 static const struct of_device_id imx_rproc_of_match
[] = {
405 { .compatible
= "fsl,imx7d-cm4", .data
= &imx_rproc_cfg_imx7d
},
406 { .compatible
= "fsl,imx6sx-cm4", .data
= &imx_rproc_cfg_imx6sx
},
409 MODULE_DEVICE_TABLE(of
, imx_rproc_of_match
);
411 static struct platform_driver imx_rproc_driver
= {
412 .probe
= imx_rproc_probe
,
413 .remove
= imx_rproc_remove
,
416 .of_match_table
= imx_rproc_of_match
,
420 module_platform_driver(imx_rproc_driver
);
422 MODULE_LICENSE("GPL v2");
423 MODULE_DESCRIPTION("IMX6SX/7D remote processor control driver");
424 MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");