18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * SLIM core rproc driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2016 STMicroelectronics
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Peter Griffin <peter.griffin@linaro.org>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/clk.h>
118c2ecf20Sopenharmony_ci#include <linux/err.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/of.h>
158c2ecf20Sopenharmony_ci#include <linux/of_device.h>
168c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
178c2ecf20Sopenharmony_ci#include <linux/remoteproc.h>
188c2ecf20Sopenharmony_ci#include <linux/remoteproc/st_slim_rproc.h>
198c2ecf20Sopenharmony_ci#include "remoteproc_internal.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* SLIM core registers */
228c2ecf20Sopenharmony_ci#define SLIM_ID_OFST		0x0
238c2ecf20Sopenharmony_ci#define SLIM_VER_OFST		0x4
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define SLIM_EN_OFST		0x8
268c2ecf20Sopenharmony_ci#define SLIM_EN_RUN			BIT(0)
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define SLIM_CLK_GATE_OFST	0xC
298c2ecf20Sopenharmony_ci#define SLIM_CLK_GATE_DIS		BIT(0)
308c2ecf20Sopenharmony_ci#define SLIM_CLK_GATE_RESET		BIT(2)
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define SLIM_SLIM_PC_OFST	0x20
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* DMEM registers */
358c2ecf20Sopenharmony_ci#define SLIM_REV_ID_OFST	0x0
368c2ecf20Sopenharmony_ci#define SLIM_REV_ID_MIN_MASK		GENMASK(15, 8)
378c2ecf20Sopenharmony_ci#define SLIM_REV_ID_MIN(id)		((id & SLIM_REV_ID_MIN_MASK) >> 8)
388c2ecf20Sopenharmony_ci#define SLIM_REV_ID_MAJ_MASK		GENMASK(23, 16)
398c2ecf20Sopenharmony_ci#define SLIM_REV_ID_MAJ(id)		((id & SLIM_REV_ID_MAJ_MASK) >> 16)
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* peripherals registers */
438c2ecf20Sopenharmony_ci#define SLIM_STBUS_SYNC_OFST	0xF88
448c2ecf20Sopenharmony_ci#define SLIM_STBUS_SYNC_DIS		BIT(0)
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define SLIM_INT_SET_OFST	0xFD4
478c2ecf20Sopenharmony_ci#define SLIM_INT_CLR_OFST	0xFD8
488c2ecf20Sopenharmony_ci#define SLIM_INT_MASK_OFST	0xFDC
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define SLIM_CMD_CLR_OFST	0xFC8
518c2ecf20Sopenharmony_ci#define SLIM_CMD_MASK_OFST	0xFCC
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic const char *mem_names[ST_SLIM_MEM_MAX] = {
548c2ecf20Sopenharmony_ci	[ST_SLIM_DMEM]	= "dmem",
558c2ecf20Sopenharmony_ci	[ST_SLIM_IMEM]	= "imem",
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic int slim_clk_get(struct st_slim_rproc *slim_rproc, struct device *dev)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	int clk, err;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	for (clk = 0; clk < ST_SLIM_MAX_CLK; clk++) {
638c2ecf20Sopenharmony_ci		slim_rproc->clks[clk] = of_clk_get(dev->of_node, clk);
648c2ecf20Sopenharmony_ci		if (IS_ERR(slim_rproc->clks[clk])) {
658c2ecf20Sopenharmony_ci			err = PTR_ERR(slim_rproc->clks[clk]);
668c2ecf20Sopenharmony_ci			if (err == -EPROBE_DEFER)
678c2ecf20Sopenharmony_ci				goto err_put_clks;
688c2ecf20Sopenharmony_ci			slim_rproc->clks[clk] = NULL;
698c2ecf20Sopenharmony_ci			break;
708c2ecf20Sopenharmony_ci		}
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return 0;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cierr_put_clks:
768c2ecf20Sopenharmony_ci	while (--clk >= 0)
778c2ecf20Sopenharmony_ci		clk_put(slim_rproc->clks[clk]);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return err;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic void slim_clk_disable(struct st_slim_rproc *slim_rproc)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	int clk;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++)
878c2ecf20Sopenharmony_ci		clk_disable_unprepare(slim_rproc->clks[clk]);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int slim_clk_enable(struct st_slim_rproc *slim_rproc)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	int clk, ret;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++) {
958c2ecf20Sopenharmony_ci		ret = clk_prepare_enable(slim_rproc->clks[clk]);
968c2ecf20Sopenharmony_ci		if (ret)
978c2ecf20Sopenharmony_ci			goto err_disable_clks;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return 0;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cierr_disable_clks:
1038c2ecf20Sopenharmony_ci	while (--clk >= 0)
1048c2ecf20Sopenharmony_ci		clk_disable_unprepare(slim_rproc->clks[clk]);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	return ret;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci/*
1108c2ecf20Sopenharmony_ci * Remoteproc slim specific device handlers
1118c2ecf20Sopenharmony_ci */
1128c2ecf20Sopenharmony_cistatic int slim_rproc_start(struct rproc *rproc)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	struct device *dev = &rproc->dev;
1158c2ecf20Sopenharmony_ci	struct st_slim_rproc *slim_rproc = rproc->priv;
1168c2ecf20Sopenharmony_ci	unsigned long hw_id, hw_ver, fw_rev;
1178c2ecf20Sopenharmony_ci	u32 val;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	/* disable CPU pipeline clock & reset CPU pipeline */
1208c2ecf20Sopenharmony_ci	val = SLIM_CLK_GATE_DIS | SLIM_CLK_GATE_RESET;
1218c2ecf20Sopenharmony_ci	writel(val, slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	/* disable SLIM core STBus sync */
1248c2ecf20Sopenharmony_ci	writel(SLIM_STBUS_SYNC_DIS, slim_rproc->peri + SLIM_STBUS_SYNC_OFST);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/* enable cpu pipeline clock */
1278c2ecf20Sopenharmony_ci	writel(!SLIM_CLK_GATE_DIS,
1288c2ecf20Sopenharmony_ci		slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	/* clear int & cmd mailbox */
1318c2ecf20Sopenharmony_ci	writel(~0U, slim_rproc->peri + SLIM_INT_CLR_OFST);
1328c2ecf20Sopenharmony_ci	writel(~0U, slim_rproc->peri + SLIM_CMD_CLR_OFST);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	/* enable all channels cmd & int */
1358c2ecf20Sopenharmony_ci	writel(~0U, slim_rproc->peri + SLIM_INT_MASK_OFST);
1368c2ecf20Sopenharmony_ci	writel(~0U, slim_rproc->peri + SLIM_CMD_MASK_OFST);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/* enable cpu */
1398c2ecf20Sopenharmony_ci	writel(SLIM_EN_RUN, slim_rproc->slimcore + SLIM_EN_OFST);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	hw_id = readl_relaxed(slim_rproc->slimcore + SLIM_ID_OFST);
1428c2ecf20Sopenharmony_ci	hw_ver = readl_relaxed(slim_rproc->slimcore + SLIM_VER_OFST);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	fw_rev = readl(slim_rproc->mem[ST_SLIM_DMEM].cpu_addr +
1458c2ecf20Sopenharmony_ci			SLIM_REV_ID_OFST);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	dev_info(dev, "fw rev:%ld.%ld on SLIM %ld.%ld\n",
1488c2ecf20Sopenharmony_ci		 SLIM_REV_ID_MAJ(fw_rev), SLIM_REV_ID_MIN(fw_rev),
1498c2ecf20Sopenharmony_ci		 hw_id, hw_ver);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	return 0;
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic int slim_rproc_stop(struct rproc *rproc)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	struct st_slim_rproc *slim_rproc = rproc->priv;
1578c2ecf20Sopenharmony_ci	u32 val;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* mask all (cmd & int) channels */
1608c2ecf20Sopenharmony_ci	writel(0UL, slim_rproc->peri + SLIM_INT_MASK_OFST);
1618c2ecf20Sopenharmony_ci	writel(0UL, slim_rproc->peri + SLIM_CMD_MASK_OFST);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/* disable cpu pipeline clock */
1648c2ecf20Sopenharmony_ci	writel(SLIM_CLK_GATE_DIS, slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	writel(!SLIM_EN_RUN, slim_rproc->slimcore + SLIM_EN_OFST);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	val = readl(slim_rproc->slimcore + SLIM_EN_OFST);
1698c2ecf20Sopenharmony_ci	if (val & SLIM_EN_RUN)
1708c2ecf20Sopenharmony_ci		dev_warn(&rproc->dev, "Failed to disable SLIM");
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	dev_dbg(&rproc->dev, "slim stopped\n");
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	return 0;
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	struct st_slim_rproc *slim_rproc = rproc->priv;
1808c2ecf20Sopenharmony_ci	void *va = NULL;
1818c2ecf20Sopenharmony_ci	int i;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	for (i = 0; i < ST_SLIM_MEM_MAX; i++) {
1848c2ecf20Sopenharmony_ci		if (da != slim_rproc->mem[i].bus_addr)
1858c2ecf20Sopenharmony_ci			continue;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci		if (len <= slim_rproc->mem[i].size) {
1888c2ecf20Sopenharmony_ci			/* __force to make sparse happy with type conversion */
1898c2ecf20Sopenharmony_ci			va = (__force void *)slim_rproc->mem[i].cpu_addr;
1908c2ecf20Sopenharmony_ci			break;
1918c2ecf20Sopenharmony_ci		}
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%zx va = 0x%pK\n",
1958c2ecf20Sopenharmony_ci		da, len, va);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return va;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic const struct rproc_ops slim_rproc_ops = {
2018c2ecf20Sopenharmony_ci	.start		= slim_rproc_start,
2028c2ecf20Sopenharmony_ci	.stop		= slim_rproc_stop,
2038c2ecf20Sopenharmony_ci	.da_to_va       = slim_rproc_da_to_va,
2048c2ecf20Sopenharmony_ci	.get_boot_addr	= rproc_elf_get_boot_addr,
2058c2ecf20Sopenharmony_ci	.load		= rproc_elf_load_segments,
2068c2ecf20Sopenharmony_ci	.sanity_check	= rproc_elf_sanity_check,
2078c2ecf20Sopenharmony_ci};
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci/**
2108c2ecf20Sopenharmony_ci * st_slim_rproc_alloc() - allocate and initialise slim rproc
2118c2ecf20Sopenharmony_ci * @pdev: Pointer to the platform_device struct
2128c2ecf20Sopenharmony_ci * @fw_name: Name of firmware for rproc to use
2138c2ecf20Sopenharmony_ci *
2148c2ecf20Sopenharmony_ci * Function for allocating and initialising a slim rproc for use by
2158c2ecf20Sopenharmony_ci * device drivers whose IP is based around the SLIM core. It
2168c2ecf20Sopenharmony_ci * obtains and enables any clocks required by the SLIM core and also
2178c2ecf20Sopenharmony_ci * ioremaps the various IO.
2188c2ecf20Sopenharmony_ci *
2198c2ecf20Sopenharmony_ci * Returns st_slim_rproc pointer or PTR_ERR() on error.
2208c2ecf20Sopenharmony_ci */
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistruct st_slim_rproc *st_slim_rproc_alloc(struct platform_device *pdev,
2238c2ecf20Sopenharmony_ci				char *fw_name)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
2268c2ecf20Sopenharmony_ci	struct st_slim_rproc *slim_rproc;
2278c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
2288c2ecf20Sopenharmony_ci	struct rproc *rproc;
2298c2ecf20Sopenharmony_ci	struct resource *res;
2308c2ecf20Sopenharmony_ci	int err, i;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (!fw_name)
2338c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (!of_device_is_compatible(np, "st,slim-rproc"))
2368c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	rproc = rproc_alloc(dev, np->name, &slim_rproc_ops,
2398c2ecf20Sopenharmony_ci			fw_name, sizeof(*slim_rproc));
2408c2ecf20Sopenharmony_ci	if (!rproc)
2418c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	rproc->has_iommu = false;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	slim_rproc = rproc->priv;
2468c2ecf20Sopenharmony_ci	slim_rproc->rproc = rproc;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	/* get imem and dmem */
2498c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
2508c2ecf20Sopenharmony_ci		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
2518c2ecf20Sopenharmony_ci						mem_names[i]);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci		slim_rproc->mem[i].cpu_addr = devm_ioremap_resource(dev, res);
2548c2ecf20Sopenharmony_ci		if (IS_ERR(slim_rproc->mem[i].cpu_addr)) {
2558c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "devm_ioremap_resource failed\n");
2568c2ecf20Sopenharmony_ci			err = PTR_ERR(slim_rproc->mem[i].cpu_addr);
2578c2ecf20Sopenharmony_ci			goto err;
2588c2ecf20Sopenharmony_ci		}
2598c2ecf20Sopenharmony_ci		slim_rproc->mem[i].bus_addr = res->start;
2608c2ecf20Sopenharmony_ci		slim_rproc->mem[i].size = resource_size(res);
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "slimcore");
2648c2ecf20Sopenharmony_ci	slim_rproc->slimcore = devm_ioremap_resource(dev, res);
2658c2ecf20Sopenharmony_ci	if (IS_ERR(slim_rproc->slimcore)) {
2668c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to ioremap slimcore IO\n");
2678c2ecf20Sopenharmony_ci		err = PTR_ERR(slim_rproc->slimcore);
2688c2ecf20Sopenharmony_ci		goto err;
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "peripherals");
2728c2ecf20Sopenharmony_ci	slim_rproc->peri = devm_ioremap_resource(dev, res);
2738c2ecf20Sopenharmony_ci	if (IS_ERR(slim_rproc->peri)) {
2748c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to ioremap peripherals IO\n");
2758c2ecf20Sopenharmony_ci		err = PTR_ERR(slim_rproc->peri);
2768c2ecf20Sopenharmony_ci		goto err;
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	err = slim_clk_get(slim_rproc, dev);
2808c2ecf20Sopenharmony_ci	if (err)
2818c2ecf20Sopenharmony_ci		goto err;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	err = slim_clk_enable(slim_rproc);
2848c2ecf20Sopenharmony_ci	if (err) {
2858c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to enable clocks\n");
2868c2ecf20Sopenharmony_ci		goto err_clk_put;
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	/* Register as a remoteproc device */
2908c2ecf20Sopenharmony_ci	err = rproc_add(rproc);
2918c2ecf20Sopenharmony_ci	if (err) {
2928c2ecf20Sopenharmony_ci		dev_err(dev, "registration of slim remoteproc failed\n");
2938c2ecf20Sopenharmony_ci		goto err_clk_dis;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	return slim_rproc;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cierr_clk_dis:
2998c2ecf20Sopenharmony_ci	slim_clk_disable(slim_rproc);
3008c2ecf20Sopenharmony_cierr_clk_put:
3018c2ecf20Sopenharmony_ci	for (i = 0; i < ST_SLIM_MAX_CLK && slim_rproc->clks[i]; i++)
3028c2ecf20Sopenharmony_ci		clk_put(slim_rproc->clks[i]);
3038c2ecf20Sopenharmony_cierr:
3048c2ecf20Sopenharmony_ci	rproc_free(rproc);
3058c2ecf20Sopenharmony_ci	return ERR_PTR(err);
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(st_slim_rproc_alloc);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci/**
3108c2ecf20Sopenharmony_ci  * st_slim_rproc_put() - put slim rproc resources
3118c2ecf20Sopenharmony_ci  * @slim_rproc: Pointer to the st_slim_rproc struct
3128c2ecf20Sopenharmony_ci  *
3138c2ecf20Sopenharmony_ci  * Function for calling respective _put() functions on slim_rproc resources.
3148c2ecf20Sopenharmony_ci  *
3158c2ecf20Sopenharmony_ci  */
3168c2ecf20Sopenharmony_civoid st_slim_rproc_put(struct st_slim_rproc *slim_rproc)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	int clk;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (!slim_rproc)
3218c2ecf20Sopenharmony_ci		return;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	slim_clk_disable(slim_rproc);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++)
3268c2ecf20Sopenharmony_ci		clk_put(slim_rproc->clks[clk]);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	rproc_del(slim_rproc->rproc);
3298c2ecf20Sopenharmony_ci	rproc_free(slim_rproc->rproc);
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(st_slim_rproc_put);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ciMODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>");
3348c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("STMicroelectronics SLIM core rproc driver");
3358c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
336