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			       size_t 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%zx\n",
207		 da, len);
208	return -ENOENT;
209}
210
211static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, size_t 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%zx va = 0x%p\n",
239		da, len, va);
240
241	return va;
242}
243
244static 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,
248};
249
250static int imx_rproc_addr_init(struct imx_rproc *priv,
251			       struct platform_device *pdev)
252{
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;
257
258	/* remap required addresses */
259	for (a = 0; a < dcfg->att_size; a++) {
260		const struct imx_rproc_att *att = &dcfg->att[a];
261
262		if (!(att->flags & ATT_OWN))
263			continue;
264
265		if (b >= IMX7D_RPROC_MEM_MAX)
266			break;
267
268		priv->mem[b].cpu_addr = devm_ioremap(&pdev->dev,
269						     att->sa, att->size);
270		if (!priv->mem[b].cpu_addr) {
271			dev_err(dev, "devm_ioremap_resource failed\n");
272			return -ENOMEM;
273		}
274		priv->mem[b].sys_addr = att->sa;
275		priv->mem[b].size = att->size;
276		b++;
277	}
278
279	/* memory-region is optional property */
280	nph = of_count_phandle_with_args(np, "memory-region", NULL);
281	if (nph <= 0)
282		return 0;
283
284	/* remap optional addresses */
285	for (a = 0; a < nph; a++) {
286		struct device_node *node;
287		struct resource res;
288
289		node = of_parse_phandle(np, "memory-region", a);
290		err = of_address_to_resource(node, 0, &res);
291		if (err) {
292			dev_err(dev, "unable to resolve memory region\n");
293			return err;
294		}
295
296		if (b >= IMX7D_RPROC_MEM_MAX)
297			break;
298
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);
303			return err;
304		}
305		priv->mem[b].sys_addr = res.start;
306		priv->mem[b].size = resource_size(&res);
307		b++;
308	}
309
310	return 0;
311}
312
313static int imx_rproc_probe(struct platform_device *pdev)
314{
315	struct device *dev = &pdev->dev;
316	struct device_node *np = dev->of_node;
317	struct imx_rproc *priv;
318	struct rproc *rproc;
319	struct regmap_config config = { .name = "imx-rproc" };
320	const struct imx_rproc_dcfg *dcfg;
321	struct regmap *regmap;
322	int ret;
323
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);
328	}
329	regmap_attach_dev(dev, regmap, &config);
330
331	/* set some other name then imx */
332	rproc = rproc_alloc(dev, "imx-rproc", &imx_rproc_ops,
333			    NULL, sizeof(*priv));
334	if (!rproc)
335		return -ENOMEM;
336
337	dcfg = of_device_get_match_data(dev);
338	if (!dcfg) {
339		ret = -EINVAL;
340		goto err_put_rproc;
341	}
342
343	priv = rproc->priv;
344	priv->rproc = rproc;
345	priv->regmap = regmap;
346	priv->dcfg = dcfg;
347	priv->dev = dev;
348
349	dev_set_drvdata(dev, rproc);
350
351	ret = imx_rproc_addr_init(priv, pdev);
352	if (ret) {
353		dev_err(dev, "failed on imx_rproc_addr_init\n");
354		goto err_put_rproc;
355	}
356
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);
361		goto err_put_rproc;
362	}
363
364	/*
365	 * clk for M4 block including memory. Should be
366	 * enabled before .start for FW transfer.
367	 */
368	ret = clk_prepare_enable(priv->clk);
369	if (ret) {
370		dev_err(&rproc->dev, "Failed to enable clock\n");
371		goto err_put_rproc;
372	}
373
374	ret = rproc_add(rproc);
375	if (ret) {
376		dev_err(dev, "rproc_add failed\n");
377		goto err_put_clk;
378	}
379
380	return 0;
381
382err_put_clk:
383	clk_disable_unprepare(priv->clk);
384err_put_rproc:
385	rproc_free(rproc);
386
387	return ret;
388}
389
390static int imx_rproc_remove(struct platform_device *pdev)
391{
392	struct rproc *rproc = platform_get_drvdata(pdev);
393	struct imx_rproc *priv = rproc->priv;
394
395	clk_disable_unprepare(priv->clk);
396	rproc_del(rproc);
397	rproc_free(rproc);
398
399	return 0;
400}
401
402static 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 },
405	{},
406};
407MODULE_DEVICE_TABLE(of, imx_rproc_of_match);
408
409static struct platform_driver imx_rproc_driver = {
410	.probe = imx_rproc_probe,
411	.remove = imx_rproc_remove,
412	.driver = {
413		.name = "imx-rproc",
414		.of_match_table = imx_rproc_of_match,
415	},
416};
417
418module_platform_driver(imx_rproc_driver);
419
420MODULE_LICENSE("GPL v2");
421MODULE_DESCRIPTION("IMX6SX/7D remote processor control driver");
422MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");