summaryrefslogtreecommitdiffstats
path: root/drivers/remoteproc
diff options
context:
space:
mode:
authorPeter Griffin <peter.griffin@linaro.org>2016-10-18 05:39:06 -0400
committerVinod Koul <vinod.koul@intel.com>2016-10-18 10:42:05 -0400
commitbb6869b2147817385e0261f928b942f466f74a63 (patch)
tree17b5d6383bd6c1bfed5b64b01450fa59ca0ce00a /drivers/remoteproc
parent1001354ca34179f3db924eb66672442a173147dc (diff)
remoteproc: st_slim_rproc: add a slimcore rproc driver
slim core is used as a basis for many IPs in the STi chipsets such as fdma and demux. To avoid duplicating the elf loading code in each device driver a slim rproc driver has been created. This driver is designed to be used by other device drivers such as fdma, or demux whose IP is based around a slim core. The device driver can call slim_rproc_alloc() to allocate a slim rproc and slim_rproc_put() when finished. This driver takes care of ioremapping the slim registers (dmem, imem, slimcore, peripherals), whose offsets and sizes can change between IP's. It also obtains and enables any clocks used by the device. This approach avoids having a double mapping of the registers as slim_rproc does not register its own platform device. It also maps well to device tree abstraction as it allows us to have one dt node for the whole device. All of the generic rproc elf loading code can be reused, and we provide start() stop() hooks to start and stop the slim core once the firmware has been loaded. This has been tested successfully with fdma driver. Signed-off-by: Peter Griffin <peter.griffin@linaro.org> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/remoteproc')
-rw-r--r--drivers/remoteproc/Kconfig7
-rw-r--r--drivers/remoteproc/Makefile1
-rw-r--r--drivers/remoteproc/st_slim_rproc.c364
3 files changed, 370 insertions, 2 deletions
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index f396bfef5d42..9270c8e596f7 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -58,7 +58,6 @@ config DA8XX_REMOTEPROC
58 tristate "DA8xx/OMAP-L13x remoteproc support" 58 tristate "DA8xx/OMAP-L13x remoteproc support"
59 depends on ARCH_DAVINCI_DA8XX 59 depends on ARCH_DAVINCI_DA8XX
60 select CMA if MMU 60 select CMA if MMU
61 select REMOTEPROC
62 select RPMSG_VIRTIO 61 select RPMSG_VIRTIO
63 help 62 help
64 Say y here to support DA8xx/OMAP-L13x remote processors via the 63 Say y here to support DA8xx/OMAP-L13x remote processors via the
@@ -99,10 +98,10 @@ config QCOM_WCNSS_PIL
99 tristate "Qualcomm WCNSS Peripheral Image Loader" 98 tristate "Qualcomm WCNSS Peripheral Image Loader"
100 depends on OF && ARCH_QCOM 99 depends on OF && ARCH_QCOM
101 depends on QCOM_SMEM 100 depends on QCOM_SMEM
101 depends on REMOTEPROC
102 select QCOM_MDT_LOADER 102 select QCOM_MDT_LOADER
103 select QCOM_SCM 103 select QCOM_SCM
104 select QCOM_WCNSS_IRIS 104 select QCOM_WCNSS_IRIS
105 select REMOTEPROC
106 help 105 help
107 Say y here to support the Peripheral Image Loader for the Qualcomm 106 Say y here to support the Peripheral Image Loader for the Qualcomm
108 Wireless Connectivity Subsystem. 107 Wireless Connectivity Subsystem.
@@ -116,4 +115,8 @@ config ST_REMOTEPROC
116 processor framework. 115 processor framework.
117 This can be either built-in or a loadable module. 116 This can be either built-in or a loadable module.
118 117
118config ST_SLIM_REMOTEPROC
119 tristate
120 select REMOTEPROC
121
119endmenu 122endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 6dfb62ed643f..924f0cb25470 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_QCOM_Q6V5_PIL) += qcom_q6v5_pil.o
16obj-$(CONFIG_QCOM_WCNSS_IRIS) += qcom_wcnss_iris.o 16obj-$(CONFIG_QCOM_WCNSS_IRIS) += qcom_wcnss_iris.o
17obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss.o 17obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss.o
18obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o 18obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o
19obj-$(CONFIG_ST_SLIM_REMOTEPROC) += st_slim_rproc.o
diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
new file mode 100644
index 000000000000..1484e9717946
--- /dev/null
+++ b/drivers/remoteproc/st_slim_rproc.c
@@ -0,0 +1,364 @@
1/*
2 * SLIM core rproc driver
3 *
4 * Copyright (C) 2016 STMicroelectronics
5 *
6 * Author: Peter Griffin <peter.griffin@linaro.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <linux/clk.h>
15#include <linux/err.h>
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/of_device.h>
20#include <linux/platform_device.h>
21#include <linux/remoteproc.h>
22#include <linux/remoteproc/st_slim_rproc.h>
23#include "remoteproc_internal.h"
24
25/* SLIM core registers */
26#define SLIM_ID_OFST 0x0
27#define SLIM_VER_OFST 0x4
28
29#define SLIM_EN_OFST 0x8
30#define SLIM_EN_RUN BIT(0)
31
32#define SLIM_CLK_GATE_OFST 0xC
33#define SLIM_CLK_GATE_DIS BIT(0)
34#define SLIM_CLK_GATE_RESET BIT(2)
35
36#define SLIM_SLIM_PC_OFST 0x20
37
38/* DMEM registers */
39#define SLIM_REV_ID_OFST 0x0
40#define SLIM_REV_ID_MIN_MASK GENMASK(15, 8)
41#define SLIM_REV_ID_MIN(id) ((id & SLIM_REV_ID_MIN_MASK) >> 8)
42#define SLIM_REV_ID_MAJ_MASK GENMASK(23, 16)
43#define SLIM_REV_ID_MAJ(id) ((id & SLIM_REV_ID_MAJ_MASK) >> 16)
44
45
46/* peripherals registers */
47#define SLIM_STBUS_SYNC_OFST 0xF88
48#define SLIM_STBUS_SYNC_DIS BIT(0)
49
50#define SLIM_INT_SET_OFST 0xFD4
51#define SLIM_INT_CLR_OFST 0xFD8
52#define SLIM_INT_MASK_OFST 0xFDC
53
54#define SLIM_CMD_CLR_OFST 0xFC8
55#define SLIM_CMD_MASK_OFST 0xFCC
56
57static const char *mem_names[ST_SLIM_MEM_MAX] = {
58 [ST_SLIM_DMEM] = "dmem",
59 [ST_SLIM_IMEM] = "imem",
60};
61
62static int slim_clk_get(struct st_slim_rproc *slim_rproc, struct device *dev)
63{
64 int clk, err;
65
66 for (clk = 0; clk < ST_SLIM_MAX_CLK; clk++) {
67 slim_rproc->clks[clk] = of_clk_get(dev->of_node, clk);
68 if (IS_ERR(slim_rproc->clks[clk])) {
69 err = PTR_ERR(slim_rproc->clks[clk]);
70 if (err == -EPROBE_DEFER)
71 goto err_put_clks;
72 slim_rproc->clks[clk] = NULL;
73 break;
74 }
75 }
76
77 return 0;
78
79err_put_clks:
80 while (--clk >= 0)
81 clk_put(slim_rproc->clks[clk]);
82
83 return err;
84}
85
86static void slim_clk_disable(struct st_slim_rproc *slim_rproc)
87{
88 int clk;
89
90 for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++)
91 clk_disable_unprepare(slim_rproc->clks[clk]);
92}
93
94static int slim_clk_enable(struct st_slim_rproc *slim_rproc)
95{
96 int clk, ret;
97
98 for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++) {
99 ret = clk_prepare_enable(slim_rproc->clks[clk]);
100 if (ret)
101 goto err_disable_clks;
102 }
103
104 return 0;
105
106err_disable_clks:
107 while (--clk >= 0)
108 clk_disable_unprepare(slim_rproc->clks[clk]);
109
110 return ret;
111}
112
113/*
114 * Remoteproc slim specific device handlers
115 */
116static int slim_rproc_start(struct rproc *rproc)
117{
118 struct device *dev = &rproc->dev;
119 struct st_slim_rproc *slim_rproc = rproc->priv;
120 unsigned long hw_id, hw_ver, fw_rev;
121 u32 val;
122
123 /* disable CPU pipeline clock & reset CPU pipeline */
124 val = SLIM_CLK_GATE_DIS | SLIM_CLK_GATE_RESET;
125 writel(val, slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
126
127 /* disable SLIM core STBus sync */
128 writel(SLIM_STBUS_SYNC_DIS, slim_rproc->peri + SLIM_STBUS_SYNC_OFST);
129
130 /* enable cpu pipeline clock */
131 writel(!SLIM_CLK_GATE_DIS,
132 slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
133
134 /* clear int & cmd mailbox */
135 writel(~0U, slim_rproc->peri + SLIM_INT_CLR_OFST);
136 writel(~0U, slim_rproc->peri + SLIM_CMD_CLR_OFST);
137
138 /* enable all channels cmd & int */
139 writel(~0U, slim_rproc->peri + SLIM_INT_MASK_OFST);
140 writel(~0U, slim_rproc->peri + SLIM_CMD_MASK_OFST);
141
142 /* enable cpu */
143 writel(SLIM_EN_RUN, slim_rproc->slimcore + SLIM_EN_OFST);
144
145 hw_id = readl_relaxed(slim_rproc->slimcore + SLIM_ID_OFST);
146 hw_ver = readl_relaxed(slim_rproc->slimcore + SLIM_VER_OFST);
147
148 fw_rev = readl(slim_rproc->mem[ST_SLIM_DMEM].cpu_addr +
149 SLIM_REV_ID_OFST);
150
151 dev_info(dev, "fw rev:%ld.%ld on SLIM %ld.%ld\n",
152 SLIM_REV_ID_MAJ(fw_rev), SLIM_REV_ID_MIN(fw_rev),
153 hw_id, hw_ver);
154
155 return 0;
156}
157
158static int slim_rproc_stop(struct rproc *rproc)
159{
160 struct st_slim_rproc *slim_rproc = rproc->priv;
161 u32 val;
162
163 /* mask all (cmd & int) channels */
164 writel(0UL, slim_rproc->peri + SLIM_INT_MASK_OFST);
165 writel(0UL, slim_rproc->peri + SLIM_CMD_MASK_OFST);
166
167 /* disable cpu pipeline clock */
168 writel(SLIM_CLK_GATE_DIS, slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
169
170 writel(!SLIM_EN_RUN, slim_rproc->slimcore + SLIM_EN_OFST);
171
172 val = readl(slim_rproc->slimcore + SLIM_EN_OFST);
173 if (val & SLIM_EN_RUN)
174 dev_warn(&rproc->dev, "Failed to disable SLIM");
175
176 dev_dbg(&rproc->dev, "slim stopped\n");
177
178 return 0;
179}
180
181static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
182{
183 struct st_slim_rproc *slim_rproc = rproc->priv;
184 void *va = NULL;
185 int i;
186
187 for (i = 0; i < ST_SLIM_MEM_MAX; i++) {
188 if (da != slim_rproc->mem[i].bus_addr)
189 continue;
190
191 if (len <= slim_rproc->mem[i].size) {
192 /* __force to make sparse happy with type conversion */
193 va = (__force void *)slim_rproc->mem[i].cpu_addr;
194 break;
195 }
196 }
197
198 dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
199
200 return va;
201}
202
203static struct rproc_ops slim_rproc_ops = {
204 .start = slim_rproc_start,
205 .stop = slim_rproc_stop,
206 .da_to_va = slim_rproc_da_to_va,
207};
208
209/*
210 * Firmware handler operations: sanity, boot address, load ...
211 */
212
213static struct resource_table empty_rsc_tbl = {
214 .ver = 1,
215 .num = 0,
216};
217
218static struct resource_table *slim_rproc_find_rsc_table(struct rproc *rproc,
219 const struct firmware *fw,
220 int *tablesz)
221{
222 *tablesz = sizeof(empty_rsc_tbl);
223 return &empty_rsc_tbl;
224}
225
226static struct rproc_fw_ops slim_rproc_fw_ops = {
227 .find_rsc_table = slim_rproc_find_rsc_table,
228};
229
230/**
231 * st_slim_rproc_alloc() - allocate and initialise slim rproc
232 * @pdev: Pointer to the platform_device struct
233 * @fw_name: Name of firmware for rproc to use
234 *
235 * Function for allocating and initialising a slim rproc for use by
236 * device drivers whose IP is based around the SLIM core. It
237 * obtains and enables any clocks required by the SLIM core and also
238 * ioremaps the various IO.
239 *
240 * Returns st_slim_rproc pointer or PTR_ERR() on error.
241 */
242
243struct st_slim_rproc *st_slim_rproc_alloc(struct platform_device *pdev,
244 char *fw_name)
245{
246 struct device *dev = &pdev->dev;
247 struct st_slim_rproc *slim_rproc;
248 struct device_node *np = dev->of_node;
249 struct rproc *rproc;
250 struct resource *res;
251 int err, i;
252 const struct rproc_fw_ops *elf_ops;
253
254 if (!fw_name)
255 return ERR_PTR(-EINVAL);
256
257 if (!of_device_is_compatible(np, "st,slim-rproc"))
258 return ERR_PTR(-EINVAL);
259
260 rproc = rproc_alloc(dev, np->name, &slim_rproc_ops,
261 fw_name, sizeof(*slim_rproc));
262 if (!rproc)
263 return ERR_PTR(-ENOMEM);
264
265 rproc->has_iommu = false;
266
267 slim_rproc = rproc->priv;
268 slim_rproc->rproc = rproc;
269
270 elf_ops = rproc->fw_ops;
271 /* Use some generic elf ops */
272 slim_rproc_fw_ops.load = elf_ops->load;
273 slim_rproc_fw_ops.sanity_check = elf_ops->sanity_check;
274
275 rproc->fw_ops = &slim_rproc_fw_ops;
276
277 /* get imem and dmem */
278 for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
279 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
280 mem_names[i]);
281
282 slim_rproc->mem[i].cpu_addr = devm_ioremap_resource(dev, res);
283 if (IS_ERR(slim_rproc->mem[i].cpu_addr)) {
284 dev_err(&pdev->dev, "devm_ioremap_resource failed\n");
285 err = PTR_ERR(slim_rproc->mem[i].cpu_addr);
286 goto err;
287 }
288 slim_rproc->mem[i].bus_addr = res->start;
289 slim_rproc->mem[i].size = resource_size(res);
290 }
291
292 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "slimcore");
293 slim_rproc->slimcore = devm_ioremap_resource(dev, res);
294 if (IS_ERR(slim_rproc->slimcore)) {
295 dev_err(&pdev->dev, "failed to ioremap slimcore IO\n");
296 err = PTR_ERR(slim_rproc->slimcore);
297 goto err;
298 }
299
300 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "peripherals");
301 slim_rproc->peri = devm_ioremap_resource(dev, res);
302 if (IS_ERR(slim_rproc->peri)) {
303 dev_err(&pdev->dev, "failed to ioremap peripherals IO\n");
304 err = PTR_ERR(slim_rproc->peri);
305 goto err;
306 }
307
308 err = slim_clk_get(slim_rproc, dev);
309 if (err)
310 goto err;
311
312 err = slim_clk_enable(slim_rproc);
313 if (err) {
314 dev_err(dev, "Failed to enable clocks\n");
315 goto err_clk_put;
316 }
317
318 /* Register as a remoteproc device */
319 err = rproc_add(rproc);
320 if (err) {
321 dev_err(dev, "registration of slim remoteproc failed\n");
322 goto err_clk_dis;
323 }
324
325 return slim_rproc;
326
327err_clk_dis:
328 slim_clk_disable(slim_rproc);
329err_clk_put:
330 for (i = 0; i < ST_SLIM_MAX_CLK && slim_rproc->clks[i]; i++)
331 clk_put(slim_rproc->clks[i]);
332err:
333 rproc_put(rproc);
334 return ERR_PTR(err);
335}
336EXPORT_SYMBOL(st_slim_rproc_alloc);
337
338/**
339 * st_slim_rproc_put() - put slim rproc resources
340 * @slim_rproc: Pointer to the st_slim_rproc struct
341 *
342 * Function for calling respective _put() functions on slim_rproc resources.
343 *
344 */
345void st_slim_rproc_put(struct st_slim_rproc *slim_rproc)
346{
347 int clk;
348
349 if (!slim_rproc)
350 return;
351
352 slim_clk_disable(slim_rproc);
353
354 for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++)
355 clk_put(slim_rproc->clks[clk]);
356
357 rproc_del(slim_rproc->rproc);
358 rproc_put(slim_rproc->rproc);
359}
360EXPORT_SYMBOL(st_slim_rproc_put);
361
362MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>");
363MODULE_DESCRIPTION("STMicroelectronics SLIM core rproc driver");
364MODULE_LICENSE("GPL v2");