Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
  4 */
  5
  6#include <linux/clk.h>
  7#include <linux/err.h>
  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>
 17
 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)
 23
 24#define IMX7D_M4_RST_MASK		(IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \
 25					 | IMX7D_SW_M4C_RST \
 26					 | IMX7D_SW_M4C_NON_SCLR_RST)
 27
 28#define IMX7D_M4_START			(IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \
 29					 | IMX7D_SW_M4C_RST)
 30#define IMX7D_M4_STOP			IMX7D_SW_M4C_NON_SCLR_RST
 31
 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)
 38
 39#define IMX6SX_M4_START			(IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \
 40					 | IMX6SX_SW_M4C_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 \
 44					 | IMX6SX_SW_M4C_RST)
 45
 46#define IMX7D_RPROC_MEM_MAX		8
 47
 48/**
 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
 53 */
 54struct imx_rproc_mem {
 55	void __iomem *cpu_addr;
 56	phys_addr_t sys_addr;
 57	size_t size;
 58};
 59
 60/* att flags */
 61/* M4 own area. Can be mapped at probe */
 62#define ATT_OWN		BIT(1)
 63
 64/* address translation table */
 65struct 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 */
 69	int flags;
 70};
 71
 72struct imx_rproc_dcfg {
 73	u32				src_reg;
 74	u32				src_mask;
 75	u32				src_start;
 76	u32				src_stop;
 77	const struct imx_rproc_att	*att;
 78	size_t				att_size;
 79};
 80
 81struct imx_rproc {
 82	struct device			*dev;
 83	struct regmap			*regmap;
 84	struct rproc			*rproc;
 85	const struct imx_rproc_dcfg	*dcfg;
 86	struct imx_rproc_mem		mem[IMX7D_RPROC_MEM_MAX];
 87	struct clk			*clk;
 88};
 89
 90static 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 },
 94	/* OCRAM_S (Code) */
 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 },
102	/* TCML (Code) */
103	{ 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN },
104	/* DDR (Code) - alias, first part of DDR (Data) */
105	{ 0x10000000, 0x80000000, 0x0FFF0000, 0 },
106
107	/* TCMU (Data) */
108	{ 0x20000000, 0x00800000, 0x00008000, ATT_OWN },
109	/* OCRAM (Data) */
110	{ 0x20200000, 0x00900000, 0x00020000, 0 },
111	/* OCRAM_EPDC (Data) */
112	{ 0x20220000, 0x00920000, 0x00020000, 0 },
113	/* OCRAM_PXP (Data) */
114	{ 0x20240000, 0x00940000, 0x00008000, 0 },
115	/* DDR (Data) */
116	{ 0x80000000, 0x80000000, 0x60000000, 0 },
117};
118
119static 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 },
123	/* OCRAM_S (Code) */
124	{ 0x00180000, 0x008F8000, 0x00004000, 0 },
125	/* OCRAM_S (Code) - alias */
126	{ 0x00180000, 0x008FC000, 0x00004000, 0 },
127	/* TCML (Code) */
128	{ 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN },
129	/* DDR (Code) - alias, first part of DDR (Data) */
130	{ 0x10000000, 0x80000000, 0x0FFF8000, 0 },
131
132	/* TCMU (Data) */
133	{ 0x20000000, 0x00800000, 0x00008000, ATT_OWN },
134	/* OCRAM_S (Data) - alias? */
135	{ 0x208F8000, 0x008F8000, 0x00004000, 0 },
136	/* DDR (Data) */
137	{ 0x80000000, 0x80000000, 0x60000000, 0 },
138};
139
140static 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),
147};
148
149static 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),
156};
157
158static int imx_rproc_start(struct rproc *rproc)
159{
160	struct imx_rproc *priv = rproc->priv;
161	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
162	struct device *dev = priv->dev;
163	int ret;
164
165	ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
166				 dcfg->src_mask, dcfg->src_start);
167	if (ret)
168		dev_err(dev, "Failed to enable M4!\n");
169
170	return ret;
171}
172
173static int imx_rproc_stop(struct rproc *rproc)
174{
175	struct imx_rproc *priv = rproc->priv;
176	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
177	struct device *dev = priv->dev;
178	int ret;
179
180	ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
181				 dcfg->src_mask, dcfg->src_stop);
182	if (ret)
183		dev_err(dev, "Failed to stop M4!\n");
184
185	return ret;
186}
187
188static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
189			       int len, u64 *sys)
190{
191	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
192	int i;
193
194	/* parse address translation table */
195	for (i = 0; i < dcfg->att_size; i++) {
196		const struct imx_rproc_att *att = &dcfg->att[i];
197
198		if (da >= att->da && da + len < att->da + att->size) {
199			unsigned int offset = da - att->da;
200
201			*sys = att->sa + offset;
202			return 0;
203		}
204	}
205
206	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
207		 da, len);
208	return -ENOENT;
209}
210
211static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
212{
213	struct imx_rproc *priv = rproc->priv;
214	void *va = NULL;
215	u64 sys;
216	int i;
217
218	if (len <= 0)
219		return NULL;
220
221	/*
222	 * On device side we have many aliases, so we need to convert device
223	 * address (M4) to system bus address first.
224	 */
225	if (imx_rproc_da_to_sys(priv, da, len, &sys))
226		return NULL;
227
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);
234			break;
235		}
236	}
237
238	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
239
240	return va;
241}
242
243static const struct rproc_ops imx_rproc_ops = {
244	.start		= imx_rproc_start,
245	.stop		= imx_rproc_stop,
246	.da_to_va       = imx_rproc_da_to_va,
247};
248
249static int imx_rproc_addr_init(struct imx_rproc *priv,
250			       struct platform_device *pdev)
251{
252	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
253	struct device *dev = &pdev->dev;
254	struct device_node *np = dev->of_node;
255	int a, b = 0, err, nph;
256
257	/* remap required addresses */
258	for (a = 0; a < dcfg->att_size; a++) {
259		const struct imx_rproc_att *att = &dcfg->att[a];
260
261		if (!(att->flags & ATT_OWN))
262			continue;
263
264		if (b >= IMX7D_RPROC_MEM_MAX)
265			break;
266
267		priv->mem[b].cpu_addr = devm_ioremap(&pdev->dev,
268						     att->sa, att->size);
269		if (!priv->mem[b].cpu_addr) {
270			dev_err(dev, "devm_ioremap_resource failed\n");
271			return -ENOMEM;
272		}
273		priv->mem[b].sys_addr = att->sa;
274		priv->mem[b].size = att->size;
275		b++;
276	}
277
278	/* memory-region is optional property */
279	nph = of_count_phandle_with_args(np, "memory-region", NULL);
280	if (nph <= 0)
281		return 0;
282
283	/* remap optional addresses */
284	for (a = 0; a < nph; a++) {
285		struct device_node *node;
286		struct resource res;
287
288		node = of_parse_phandle(np, "memory-region", a);
289		err = of_address_to_resource(node, 0, &res);
290		if (err) {
291			dev_err(dev, "unable to resolve memory region\n");
292			return err;
293		}
294
295		if (b >= IMX7D_RPROC_MEM_MAX)
296			break;
297
298		priv->mem[b].cpu_addr = devm_ioremap_resource(&pdev->dev, &res);
299		if (IS_ERR(priv->mem[b].cpu_addr)) {
300			dev_err(dev, "devm_ioremap_resource failed\n");
301			err = PTR_ERR(priv->mem[b].cpu_addr);
302			return err;
303		}
304		priv->mem[b].sys_addr = res.start;
305		priv->mem[b].size = resource_size(&res);
306		b++;
307	}
308
309	return 0;
310}
311
312static int imx_rproc_probe(struct platform_device *pdev)
313{
314	struct device *dev = &pdev->dev;
315	struct device_node *np = dev->of_node;
316	struct imx_rproc *priv;
317	struct rproc *rproc;
318	struct regmap_config config = { .name = "imx-rproc" };
319	const struct imx_rproc_dcfg *dcfg;
320	struct regmap *regmap;
321	int ret;
322
323	regmap = syscon_regmap_lookup_by_phandle(np, "syscon");
324	if (IS_ERR(regmap)) {
325		dev_err(dev, "failed to find syscon\n");
326		return PTR_ERR(regmap);
327	}
328	regmap_attach_dev(dev, regmap, &config);
329
330	/* set some other name then imx */
331	rproc = rproc_alloc(dev, "imx-rproc", &imx_rproc_ops,
332			    NULL, sizeof(*priv));
333	if (!rproc)
334		return -ENOMEM;
335
336	dcfg = of_device_get_match_data(dev);
337	if (!dcfg) {
338		ret = -EINVAL;
339		goto err_put_rproc;
340	}
341
342	priv = rproc->priv;
343	priv->rproc = rproc;
344	priv->regmap = regmap;
345	priv->dcfg = dcfg;
346	priv->dev = dev;
347
348	dev_set_drvdata(dev, rproc);
349
350	ret = imx_rproc_addr_init(priv, pdev);
351	if (ret) {
352		dev_err(dev, "failed on imx_rproc_addr_init\n");
353		goto err_put_rproc;
354	}
355
356	priv->clk = devm_clk_get(dev, NULL);
357	if (IS_ERR(priv->clk)) {
358		dev_err(dev, "Failed to get clock\n");
359		ret = PTR_ERR(priv->clk);
360		goto err_put_rproc;
361	}
362
363	/*
364	 * clk for M4 block including memory. Should be
365	 * enabled before .start for FW transfer.
366	 */
367	ret = clk_prepare_enable(priv->clk);
368	if (ret) {
369		dev_err(&rproc->dev, "Failed to enable clock\n");
370		goto err_put_rproc;
371	}
372
373	ret = rproc_add(rproc);
374	if (ret) {
375		dev_err(dev, "rproc_add failed\n");
376		goto err_put_clk;
377	}
378
379	return 0;
380
381err_put_clk:
382	clk_disable_unprepare(priv->clk);
383err_put_rproc:
384	rproc_free(rproc);
385
386	return ret;
387}
388
389static int imx_rproc_remove(struct platform_device *pdev)
390{
391	struct rproc *rproc = platform_get_drvdata(pdev);
392	struct imx_rproc *priv = rproc->priv;
393
394	clk_disable_unprepare(priv->clk);
395	rproc_del(rproc);
396	rproc_free(rproc);
397
398	return 0;
399}
400
401static const struct of_device_id imx_rproc_of_match[] = {
402	{ .compatible = "fsl,imx7d-cm4", .data = &imx_rproc_cfg_imx7d },
403	{ .compatible = "fsl,imx6sx-cm4", .data = &imx_rproc_cfg_imx6sx },
404	{},
405};
406MODULE_DEVICE_TABLE(of, imx_rproc_of_match);
407
408static struct platform_driver imx_rproc_driver = {
409	.probe = imx_rproc_probe,
410	.remove = imx_rproc_remove,
411	.driver = {
412		.name = "imx-rproc",
413		.of_match_table = imx_rproc_of_match,
414	},
415};
416
417module_platform_driver(imx_rproc_driver);
418
419MODULE_LICENSE("GPL v2");
420MODULE_DESCRIPTION("IMX6SX/7D remote processor control driver");
421MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");