cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

st_slim_rproc.c (8492B)


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