blob: 493a618cb7791ed156c1c2c34623f5be9ea1c4e3 [file] [log] [blame]
Per Åstrand2cd53972021-04-12 13:46:04 +02001/*
2 * Copyright (c) 2021 Arm Limited. All rights reserved.
3 *
4 * This program is free software and is provided to you under the terms of the
5 * GNU General Public License version 2 as published by the Free Software
6 * Foundation, and any use by you of this program is subject to the terms
7 * of such GNU licence.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, you can access it online at
16 * http://www.gnu.org/licenses/gpl-2.0.html.
17 *
18 * SPDX-License-Identifier: GPL-2.0-only
19 */
20
21#include <linux/firmware.h>
22#include <linux/io.h>
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/of.h>
26#include <linux/of_address.h>
27#include <linux/of_device.h>
28#include <linux/platform_device.h>
29#include <linux/remoteproc.h>
30#include <linux/reset.h>
Nir Ekhauz48239212021-11-23 10:28:34 +020031#include <linux/version.h>
Per Åstrand2cd53972021-04-12 13:46:04 +020032
33#define ETHOSU_RPROC_DRIVER_VERSION "0.0.1"
34
35#define DEFAULT_FW_FILE "arm-ethos-u65.fw"
36#define DEFAULT_AUTO_BOOT (false)
37
38/* firmware naming module parameter */
39static char fw_filename_param[256] = DEFAULT_FW_FILE;
40/* As the remoteproc is setup at probe, just allow the filename readonly */
41module_param_string(filename, fw_filename_param, sizeof(fw_filename_param),
42 0444);
43MODULE_PARM_DESC(filename,
44 "Filename for firmware image for Ethos-U remoteproc");
45
46static bool auto_boot = DEFAULT_AUTO_BOOT;
47module_param(auto_boot, bool, DEFAULT_AUTO_BOOT);
48MODULE_PARM_DESC(auto_boot, "Set to one to auto boot at load.");
49
50struct ethosu_rproc {
51 struct device *dev;
52 struct reset_control *rstc;
53 struct rproc_mem_mapping *map;
54 size_t map_size;
55};
56
57struct rproc_mem_mapping {
58 const char *name;
59 phys_addr_t rproc_addr;
60 void __iomem *vaddr;
61 size_t size;
62};
63
64struct ethosu_rproc_config {
65 struct fw_config *fw;
66};
67
68/*****************************************************************************/
69
70static int ethosu_rproc_start(struct rproc *rproc)
71{
72 struct ethosu_rproc *ethosu = (struct ethosu_rproc *)rproc->priv;
73 struct device *dev = ethosu->dev;
74
75 dev_info(dev, "Starting up Ethos-U subsystem CPU!");
76
77 return reset_control_deassert(ethosu->rstc);
78}
79
80static int ethosu_rproc_stop(struct rproc *rproc)
81{
82 struct ethosu_rproc *ethosu = (struct ethosu_rproc *)rproc->priv;
83 struct device *dev = ethosu->dev;
84
85 dev_info(dev, "Stopping Ethos-U subsystem CPU!");
86
87 return reset_control_assert(ethosu->rstc);
88}
89
90static void ethosu_rproc_kick(struct rproc *rproc,
91 int vqid)
92{
93 return;
94}
95
Nir Ekhauz48239212021-11-23 10:28:34 +020096#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0)
Per Åstrand2cd53972021-04-12 13:46:04 +020097static void *ethosu_da_to_va(struct rproc *rproc,
98 u64 da,
99 int len)
Nir Ekhauz48239212021-11-23 10:28:34 +0200100#else
101static void *ethosu_da_to_va(struct rproc *rproc,
102 u64 da,
103 size_t len,
104 bool *is_iomem)
105#endif
Per Åstrand2cd53972021-04-12 13:46:04 +0200106{
107 struct ethosu_rproc *ethosu = (struct ethosu_rproc *)rproc->priv;
108 int offset;
109 int i;
110
111 for (i = 0; i < ethosu->map_size; i++)
112 if (da >= ethosu->map[i].rproc_addr &&
113 da < (ethosu->map[i].rproc_addr + ethosu->map[i].size)) {
114 offset = da - ethosu->map[i].rproc_addr;
115 dev_info(ethosu->dev,
116 "mapping %llx to %p (offset: 0x%x)", da,
117 (void *)(ethosu->map[i].vaddr + offset),
118 offset);
119
120 return (void *)(ethosu->map[i].vaddr + offset);
121 }
122
123 return NULL;
124}
125
126static const struct rproc_ops ethosu_rproc_ops = {
127 .start = &ethosu_rproc_start,
128 .stop = &ethosu_rproc_stop,
129 .kick = &ethosu_rproc_kick,
130 .da_to_va = &ethosu_da_to_va,
131};
132
133/**
134 * Since the remote side doesn't yet support rpmsg just return an
135 * empty resource table when asked about it.
136 */
137struct resource_table *ethosu_rproc_find_rsc_table(struct rproc *rproc,
138 const struct firmware *fw,
139 int *tablesz)
140{
141 static struct resource_table table = { .ver = 1, };
142 struct ethosu_rproc *ethosu = (struct ethosu_rproc *)rproc->priv;
143
144 dev_info(ethosu->dev, "Sizeof struct resource_table : %zu",
145 sizeof(table));
146 *tablesz = sizeof(table);
147
148 return &table;
149}
150
151/*****************************************************************************/
152
153static int ethosu_rproc_of_memory_translations(struct platform_device *pdev,
154 struct ethosu_rproc *ethosu_rproc)
155{
156 const char *const of_rproc_address_cells =
157 "#ethosu,rproc-address-cells";
158 const char *const of_rproc_ranges = "ethosu,rproc-ranges";
159 const char *const of_rproc_ranges_names = "ethosu,rproc-names";
160
161 struct device *dev = &pdev->dev;
162 struct device_node *np = dev->of_node;
163 struct rproc_mem_mapping *mem_map;
164 const __be32 *rproc_ranges;
165
166 int addr_cells, rproc_addr_cells, size_cells, cells_for_array_element;
167 int i, len, cnt, name_cnt, ret = 0;
168
169 if (of_property_read_u32(np, of_rproc_address_cells,
170 &rproc_addr_cells)) {
171 dev_info(dev, "%s not defined in dtb", of_rproc_address_cells);
172
173 return -ENODEV;
174 }
175
176 addr_cells = of_n_addr_cells(np);
177 size_cells = of_n_size_cells(np);
178
179 dev_dbg(dev, "Using %d remote proc address cells for parsing mapping",
180 rproc_addr_cells);
181 dev_dbg(dev,
182 "Using %d of size %d parent address cells for parsing mapping",
183 addr_cells, size_cells);
184
185 cells_for_array_element = addr_cells + rproc_addr_cells + size_cells;
186
187 cnt = of_property_count_elems_of_size(np, of_rproc_ranges,
188 cells_for_array_element);
189 cnt /= sizeof(u32);
190
191 if (cnt <= 0) {
192 dev_info(dev, "No remoteproc memory mapping ranges found.");
193
194 return 0;
195 }
196
197 name_cnt = of_property_count_strings(np, of_rproc_ranges_names);
198 if (name_cnt > 0 && name_cnt != cnt) {
199 dev_err(dev, "Mismatch length for %s and %s", of_rproc_ranges,
200 of_rproc_ranges_names);
201
202 return -EINVAL;
203 }
204
205 mem_map = devm_kcalloc(dev, cnt, sizeof(*mem_map), GFP_KERNEL);
206 if (!mem_map)
207 return -ENOMEM;
208
209 rproc_ranges = of_get_property(np, of_rproc_ranges, &len);
210
211 for (i = 0; i < cnt; i++) {
212 struct resource *r;
213 const char *name = NULL;
214 int n;
215
216 of_property_read_string_index(np, of_rproc_ranges_names, i,
217 &name);
218 mem_map[i].name = name;
219 n = i * cells_for_array_element;
220 mem_map[i].rproc_addr =
221 of_read_number(&rproc_ranges[n + addr_cells],
222 rproc_addr_cells);
223 mem_map[i].size =
224 of_read_number(&rproc_ranges[n + addr_cells +
225 rproc_addr_cells],
226 size_cells);
227
228 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
229 if (!r) {
230 dev_err(&pdev->dev, "Failed to get '%s' resource.\n",
231 name);
232
233 return -EINVAL;
234 }
235
236 mem_map[i].vaddr = devm_ioremap_wc(dev, r->start,
237 mem_map[i].size);
238 if (IS_ERR(mem_map[i].vaddr)) {
239 dev_err(dev, "Failed to remap '%s'", name);
240
241 return PTR_ERR(mem_map[i].vaddr);
242 }
243
244 dev_dbg(dev,
245 "rproc memory mapping[%i]=%s: da %llx, va, %pa, size %zx:\n",
246 i, name, mem_map[i].rproc_addr, &mem_map[i].vaddr,
247 mem_map[i].size);
248 }
249
250 ethosu_rproc->map = mem_map;
251 ethosu_rproc->map_size = cnt;
252 dev_dbg(dev, "rproc memory mapped %zx regions", ethosu_rproc->map_size);
253
254 return ret;
255}
256
257static const struct of_device_id ethosu_rproc_match[] = {
Per Åstrand9f36f2e2021-09-30 09:57:34 +0200258 { .compatible = "arm,ethosu-rproc" },
Per Åstrand2cd53972021-04-12 13:46:04 +0200259};
260
261static int ethosu_rproc_probe(struct platform_device *pdev)
262{
263 struct device *dev = &pdev->dev;
264 struct device_node *np = dev->of_node;
265 struct ethosu_rproc *ethosu_rproc;
266 struct rproc *rproc;
267 int ret = -ENODEV;
268
269 rproc = rproc_alloc(dev, np->name, &ethosu_rproc_ops,
270 fw_filename_param,
271 sizeof(*ethosu_rproc));
272 if (!rproc) {
273 ret = -ENOMEM;
274 goto out;
275 }
276
277 /* Configure rproc */
278 rproc->has_iommu = false;
279 rproc->auto_boot = auto_boot;
280
281 platform_set_drvdata(pdev, rproc);
282
283 ethosu_rproc = rproc->priv;
284 ethosu_rproc->dev = dev;
285
286 /* Get the reset handler for the subsystem */
287 ethosu_rproc->rstc = devm_reset_control_get_exclusive_by_index(dev, 0);
288 if (IS_ERR(ethosu_rproc->rstc)) {
289 dev_err(&pdev->dev, "Failed to get reset controller.\n");
290 ret = PTR_ERR(ethosu_rproc->rstc);
291 goto free_rproc;
292 }
293
294 /* Get the translation from device memory to kernel space */
295 ret = ethosu_rproc_of_memory_translations(pdev, ethosu_rproc);
296 if (ret)
297 goto free_rproc;
298
299 ret = rproc_add(rproc);
300
301free_rproc:
302 if (ret)
303 rproc_free(rproc);
304
305out:
306
307 return ret;
308}
309
310static int ethosu_rproc_remove(struct platform_device *pdev)
311{
312 struct rproc *rproc = platform_get_drvdata(pdev);
313
314 rproc_del(rproc);
315 rproc_free(rproc);
316
317 return 0;
318}
319
320static struct platform_driver ethosu_rproc_driver = {
321 .probe = ethosu_rproc_probe,
322 .remove = ethosu_rproc_remove,
323 .driver = {
324 .name = "ethosu-rproc",
325 .of_match_table = of_match_ptr(ethosu_rproc_match),
326 },
327};
328
329module_platform_driver(ethosu_rproc_driver);
330
331MODULE_LICENSE("GPL v2");
332MODULE_AUTHOR("Arm Ltd");
333MODULE_DESCRIPTION("Arm Ethos-U NPU RemoteProc Driver");
334MODULE_VERSION(ETHOSU_RPROC_DRIVER_VERSION);