brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · cc17e84 Raw
229 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) IoT.bzh 20214 */5 6#include <linux/limits.h>7#include <linux/module.h>8#include <linux/of.h>9#include <linux/of_reserved_mem.h>10#include <linux/platform_device.h>11#include <linux/pm_runtime.h>12#include <linux/remoteproc.h>13#include <linux/reset.h>14#include <linux/soc/renesas/rcar-rst.h>15 16#include "remoteproc_internal.h"17 18struct rcar_rproc {19	struct reset_control *rst;20};21 22static int rcar_rproc_mem_alloc(struct rproc *rproc,23				 struct rproc_mem_entry *mem)24{25	struct device *dev = &rproc->dev;26	void *va;27 28	dev_dbg(dev, "map memory: %pa+%zx\n", &mem->dma, mem->len);29	va = ioremap_wc(mem->dma, mem->len);30	if (!va) {31		dev_err(dev, "Unable to map memory region: %pa+%zx\n",32			&mem->dma, mem->len);33		return -ENOMEM;34	}35 36	/* Update memory entry va */37	mem->va = va;38 39	return 0;40}41 42static int rcar_rproc_mem_release(struct rproc *rproc,43				   struct rproc_mem_entry *mem)44{45	dev_dbg(&rproc->dev, "unmap memory: %pa\n", &mem->dma);46	iounmap(mem->va);47 48	return 0;49}50 51static int rcar_rproc_prepare(struct rproc *rproc)52{53	struct device *dev = rproc->dev.parent;54	struct device_node *np = dev->of_node;55	struct of_phandle_iterator it;56	struct rproc_mem_entry *mem;57	struct reserved_mem *rmem;58	u32 da;59 60	/* Register associated reserved memory regions */61	of_phandle_iterator_init(&it, np, "memory-region", NULL, 0);62	while (of_phandle_iterator_next(&it) == 0) {63 64		rmem = of_reserved_mem_lookup(it.node);65		if (!rmem) {66			of_node_put(it.node);67			dev_err(&rproc->dev,68				"unable to acquire memory-region\n");69			return -EINVAL;70		}71 72		if (rmem->base > U32_MAX) {73			of_node_put(it.node);74			return -EINVAL;75		}76 77		/* No need to translate pa to da, R-Car use same map */78		da = rmem->base;79		mem = rproc_mem_entry_init(dev, NULL,80					   rmem->base,81					   rmem->size, da,82					   rcar_rproc_mem_alloc,83					   rcar_rproc_mem_release,84					   it.node->name);85 86		if (!mem) {87			of_node_put(it.node);88			return -ENOMEM;89		}90 91		rproc_add_carveout(rproc, mem);92	}93 94	return 0;95}96 97static int rcar_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)98{99	int ret;100 101	ret = rproc_elf_load_rsc_table(rproc, fw);102	if (ret)103		dev_info(&rproc->dev, "No resource table in elf\n");104 105	return 0;106}107 108static int rcar_rproc_start(struct rproc *rproc)109{110	struct rcar_rproc *priv = rproc->priv;111	int err;112 113	if (!rproc->bootaddr)114		return -EINVAL;115 116	err = rcar_rst_set_rproc_boot_addr(rproc->bootaddr);117	if (err) {118		dev_err(&rproc->dev, "failed to set rproc boot addr\n");119		return err;120	}121 122	err = reset_control_deassert(priv->rst);123	if (err)124		dev_err(&rproc->dev, "failed to deassert reset\n");125 126	return err;127}128 129static int rcar_rproc_stop(struct rproc *rproc)130{131	struct rcar_rproc *priv = rproc->priv;132	int err;133 134	err = reset_control_assert(priv->rst);135	if (err)136		dev_err(&rproc->dev, "failed to assert reset\n");137 138	return err;139}140 141static struct rproc_ops rcar_rproc_ops = {142	.prepare	= rcar_rproc_prepare,143	.start		= rcar_rproc_start,144	.stop		= rcar_rproc_stop,145	.load		= rproc_elf_load_segments,146	.parse_fw	= rcar_rproc_parse_fw,147	.find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,148	.sanity_check	= rproc_elf_sanity_check,149	.get_boot_addr	= rproc_elf_get_boot_addr,150 151};152 153static int rcar_rproc_probe(struct platform_device *pdev)154{155	struct device *dev = &pdev->dev;156	struct device_node *np = dev->of_node;157	struct rcar_rproc *priv;158	struct rproc *rproc;159	int ret;160 161	rproc = devm_rproc_alloc(dev, np->name, &rcar_rproc_ops,162				NULL, sizeof(*priv));163	if (!rproc)164		return -ENOMEM;165 166	priv = rproc->priv;167 168	priv->rst = devm_reset_control_get_exclusive(dev, NULL);169	if (IS_ERR(priv->rst)) {170		ret = PTR_ERR(priv->rst);171		dev_err_probe(dev, ret, "fail to acquire rproc reset\n");172		return ret;173	}174 175	pm_runtime_enable(dev);176	ret = pm_runtime_resume_and_get(dev);177	if (ret) {178		dev_err(dev, "failed to power up\n");179		return ret;180	}181 182	dev_set_drvdata(dev, rproc);183 184	/* Manually start the rproc */185	rproc->auto_boot = false;186 187	ret = devm_rproc_add(dev, rproc);188	if (ret) {189		dev_err(dev, "rproc_add failed\n");190		goto pm_disable;191	}192 193	return 0;194 195pm_disable:196	pm_runtime_disable(dev);197 198	return ret;199}200 201static void rcar_rproc_remove(struct platform_device *pdev)202{203	struct device *dev = &pdev->dev;204 205	pm_runtime_disable(dev);206}207 208static const struct of_device_id rcar_rproc_of_match[] = {209	{ .compatible = "renesas,rcar-cr7" },210	{},211};212 213MODULE_DEVICE_TABLE(of, rcar_rproc_of_match);214 215static struct platform_driver rcar_rproc_driver = {216	.probe = rcar_rproc_probe,217	.remove_new = rcar_rproc_remove,218	.driver = {219		.name = "rcar-rproc",220		.of_match_table = rcar_rproc_of_match,221	},222};223 224module_platform_driver(rcar_rproc_driver);225 226MODULE_LICENSE("GPL v2");227MODULE_DESCRIPTION("Renesas R-Car Gen3 remote processor control driver");228MODULE_AUTHOR("Julien Massot <julien.massot@iot.bzh>");229