brintos

brintos / linux-shallow public Read only

0
0
Text · 8.2 KiB · 5412beb Raw
333 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * SLIM core rproc driver4 *5 * Copyright (C) 2016 STMicroelectronics6 *7 * Author: Peter Griffin <peter.griffin@linaro.org>8 */9 10#include <linux/clk.h>11#include <linux/err.h>12#include <linux/kernel.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/platform_device.h>16#include <linux/remoteproc.h>17#include <linux/remoteproc/st_slim_rproc.h>18#include "remoteproc_internal.h"19 20/* SLIM core registers */21#define SLIM_ID_OFST		0x022#define SLIM_VER_OFST		0x423 24#define SLIM_EN_OFST		0x825#define SLIM_EN_RUN			BIT(0)26 27#define SLIM_CLK_GATE_OFST	0xC28#define SLIM_CLK_GATE_DIS		BIT(0)29#define SLIM_CLK_GATE_RESET		BIT(2)30 31#define SLIM_SLIM_PC_OFST	0x2032 33/* DMEM registers */34#define SLIM_REV_ID_OFST	0x035#define SLIM_REV_ID_MIN_MASK		GENMASK(15, 8)36#define SLIM_REV_ID_MIN(id)		((id & SLIM_REV_ID_MIN_MASK) >> 8)37#define SLIM_REV_ID_MAJ_MASK		GENMASK(23, 16)38#define SLIM_REV_ID_MAJ(id)		((id & SLIM_REV_ID_MAJ_MASK) >> 16)39 40 41/* peripherals registers */42#define SLIM_STBUS_SYNC_OFST	0xF8843#define SLIM_STBUS_SYNC_DIS		BIT(0)44 45#define SLIM_INT_SET_OFST	0xFD446#define SLIM_INT_CLR_OFST	0xFD847#define SLIM_INT_MASK_OFST	0xFDC48 49#define SLIM_CMD_CLR_OFST	0xFC850#define SLIM_CMD_MASK_OFST	0xFCC51 52static const char *mem_names[ST_SLIM_MEM_MAX] = {53	[ST_SLIM_DMEM]	= "dmem",54	[ST_SLIM_IMEM]	= "imem",55};56 57static int slim_clk_get(struct st_slim_rproc *slim_rproc, struct device *dev)58{59	int clk, err;60 61	for (clk = 0; clk < ST_SLIM_MAX_CLK; clk++) {62		slim_rproc->clks[clk] = of_clk_get(dev->of_node, clk);63		if (IS_ERR(slim_rproc->clks[clk])) {64			err = PTR_ERR(slim_rproc->clks[clk]);65			if (err == -EPROBE_DEFER)66				goto err_put_clks;67			slim_rproc->clks[clk] = NULL;68			break;69		}70	}71 72	return 0;73 74err_put_clks:75	while (--clk >= 0)76		clk_put(slim_rproc->clks[clk]);77 78	return err;79}80 81static void slim_clk_disable(struct st_slim_rproc *slim_rproc)82{83	int clk;84 85	for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++)86		clk_disable_unprepare(slim_rproc->clks[clk]);87}88 89static int slim_clk_enable(struct st_slim_rproc *slim_rproc)90{91	int clk, ret;92 93	for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++) {94		ret = clk_prepare_enable(slim_rproc->clks[clk]);95		if (ret)96			goto err_disable_clks;97	}98 99	return 0;100 101err_disable_clks:102	while (--clk >= 0)103		clk_disable_unprepare(slim_rproc->clks[clk]);104 105	return ret;106}107 108/*109 * Remoteproc slim specific device handlers110 */111static int slim_rproc_start(struct rproc *rproc)112{113	struct device *dev = &rproc->dev;114	struct st_slim_rproc *slim_rproc = rproc->priv;115	unsigned long hw_id, hw_ver, fw_rev;116	u32 val;117 118	/* disable CPU pipeline clock & reset CPU pipeline */119	val = SLIM_CLK_GATE_DIS | SLIM_CLK_GATE_RESET;120	writel(val, slim_rproc->slimcore + SLIM_CLK_GATE_OFST);121 122	/* disable SLIM core STBus sync */123	writel(SLIM_STBUS_SYNC_DIS, slim_rproc->peri + SLIM_STBUS_SYNC_OFST);124 125	/* enable cpu pipeline clock */126	writel(!SLIM_CLK_GATE_DIS,127		slim_rproc->slimcore + SLIM_CLK_GATE_OFST);128 129	/* clear int & cmd mailbox */130	writel(~0U, slim_rproc->peri + SLIM_INT_CLR_OFST);131	writel(~0U, slim_rproc->peri + SLIM_CMD_CLR_OFST);132 133	/* enable all channels cmd & int */134	writel(~0U, slim_rproc->peri + SLIM_INT_MASK_OFST);135	writel(~0U, slim_rproc->peri + SLIM_CMD_MASK_OFST);136 137	/* enable cpu */138	writel(SLIM_EN_RUN, slim_rproc->slimcore + SLIM_EN_OFST);139 140	hw_id = readl_relaxed(slim_rproc->slimcore + SLIM_ID_OFST);141	hw_ver = readl_relaxed(slim_rproc->slimcore + SLIM_VER_OFST);142 143	fw_rev = readl(slim_rproc->mem[ST_SLIM_DMEM].cpu_addr +144			SLIM_REV_ID_OFST);145 146	dev_info(dev, "fw rev:%ld.%ld on SLIM %ld.%ld\n",147		 SLIM_REV_ID_MAJ(fw_rev), SLIM_REV_ID_MIN(fw_rev),148		 hw_id, hw_ver);149 150	return 0;151}152 153static int slim_rproc_stop(struct rproc *rproc)154{155	struct st_slim_rproc *slim_rproc = rproc->priv;156	u32 val;157 158	/* mask all (cmd & int) channels */159	writel(0UL, slim_rproc->peri + SLIM_INT_MASK_OFST);160	writel(0UL, slim_rproc->peri + SLIM_CMD_MASK_OFST);161 162	/* disable cpu pipeline clock */163	writel(SLIM_CLK_GATE_DIS, slim_rproc->slimcore + SLIM_CLK_GATE_OFST);164 165	writel(!SLIM_EN_RUN, slim_rproc->slimcore + SLIM_EN_OFST);166 167	val = readl(slim_rproc->slimcore + SLIM_EN_OFST);168	if (val & SLIM_EN_RUN)169		dev_warn(&rproc->dev, "Failed to disable SLIM");170 171	dev_dbg(&rproc->dev, "slim stopped\n");172 173	return 0;174}175 176static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)177{178	struct st_slim_rproc *slim_rproc = rproc->priv;179	void *va = NULL;180	int i;181 182	for (i = 0; i < ST_SLIM_MEM_MAX; i++) {183		if (da != slim_rproc->mem[i].bus_addr)184			continue;185 186		if (len <= slim_rproc->mem[i].size) {187			/* __force to make sparse happy with type conversion */188			va = (__force void *)slim_rproc->mem[i].cpu_addr;189			break;190		}191	}192 193	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%zx va = 0x%pK\n",194		da, len, va);195 196	return va;197}198 199static const struct rproc_ops slim_rproc_ops = {200	.start		= slim_rproc_start,201	.stop		= slim_rproc_stop,202	.da_to_va       = slim_rproc_da_to_va,203	.get_boot_addr	= rproc_elf_get_boot_addr,204	.load		= rproc_elf_load_segments,205	.sanity_check	= rproc_elf_sanity_check,206};207 208/**209 * st_slim_rproc_alloc() - allocate and initialise slim rproc210 * @pdev: Pointer to the platform_device struct211 * @fw_name: Name of firmware for rproc to use212 *213 * Function for allocating and initialising a slim rproc for use by214 * device drivers whose IP is based around the SLIM core. It215 * obtains and enables any clocks required by the SLIM core and also216 * ioremaps the various IO.217 *218 * Return: st_slim_rproc pointer or PTR_ERR() on error.219 */220 221struct st_slim_rproc *st_slim_rproc_alloc(struct platform_device *pdev,222				char *fw_name)223{224	struct device *dev = &pdev->dev;225	struct st_slim_rproc *slim_rproc;226	struct device_node *np = dev->of_node;227	struct rproc *rproc;228	struct resource *res;229	int err, i;230 231	if (!fw_name)232		return ERR_PTR(-EINVAL);233 234	if (!of_device_is_compatible(np, "st,slim-rproc"))235		return ERR_PTR(-EINVAL);236 237	rproc = rproc_alloc(dev, np->name, &slim_rproc_ops,238			fw_name, sizeof(*slim_rproc));239	if (!rproc)240		return ERR_PTR(-ENOMEM);241 242	rproc->has_iommu = false;243 244	slim_rproc = rproc->priv;245	slim_rproc->rproc = rproc;246 247	/* get imem and dmem */248	for (i = 0; i < ARRAY_SIZE(mem_names); i++) {249		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,250						mem_names[i]);251 252		slim_rproc->mem[i].cpu_addr = devm_ioremap_resource(dev, res);253		if (IS_ERR(slim_rproc->mem[i].cpu_addr)) {254			dev_err(&pdev->dev, "devm_ioremap_resource failed\n");255			err = PTR_ERR(slim_rproc->mem[i].cpu_addr);256			goto err;257		}258		slim_rproc->mem[i].bus_addr = res->start;259		slim_rproc->mem[i].size = resource_size(res);260	}261 262	slim_rproc->slimcore = devm_platform_ioremap_resource_byname(pdev, "slimcore");263	if (IS_ERR(slim_rproc->slimcore)) {264		dev_err(&pdev->dev, "failed to ioremap slimcore IO\n");265		err = PTR_ERR(slim_rproc->slimcore);266		goto err;267	}268 269	slim_rproc->peri = devm_platform_ioremap_resource_byname(pdev, "peripherals");270	if (IS_ERR(slim_rproc->peri)) {271		dev_err(&pdev->dev, "failed to ioremap peripherals IO\n");272		err = PTR_ERR(slim_rproc->peri);273		goto err;274	}275 276	err = slim_clk_get(slim_rproc, dev);277	if (err)278		goto err;279 280	err = slim_clk_enable(slim_rproc);281	if (err) {282		dev_err(dev, "Failed to enable clocks\n");283		goto err_clk_put;284	}285 286	/* Register as a remoteproc device */287	err = rproc_add(rproc);288	if (err) {289		dev_err(dev, "registration of slim remoteproc failed\n");290		goto err_clk_dis;291	}292 293	return slim_rproc;294 295err_clk_dis:296	slim_clk_disable(slim_rproc);297err_clk_put:298	for (i = 0; i < ST_SLIM_MAX_CLK && slim_rproc->clks[i]; i++)299		clk_put(slim_rproc->clks[i]);300err:301	rproc_free(rproc);302	return ERR_PTR(err);303}304EXPORT_SYMBOL(st_slim_rproc_alloc);305 306/**307  * st_slim_rproc_put() - put slim rproc resources308  * @slim_rproc: Pointer to the st_slim_rproc struct309  *310  * Function for calling respective _put() functions on slim_rproc resources.311  *312  */313void st_slim_rproc_put(struct st_slim_rproc *slim_rproc)314{315	int clk;316 317	if (!slim_rproc)318		return;319 320	slim_clk_disable(slim_rproc);321 322	for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++)323		clk_put(slim_rproc->clks[clk]);324 325	rproc_del(slim_rproc->rproc);326	rproc_free(slim_rproc->rproc);327}328EXPORT_SYMBOL(st_slim_rproc_put);329 330MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>");331MODULE_DESCRIPTION("STMicroelectronics SLIM core rproc driver");332MODULE_LICENSE("GPL v2");333