blob: 9fb561a09eb0cf68b909d1b3e1605e6d1af25247 [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>
31
32#define ETHOSU_RPROC_DRIVER_VERSION "0.0.1"
33
34#define DEFAULT_FW_FILE "arm-ethos-u65.fw"
35#define DEFAULT_AUTO_BOOT (false)
36
37/* firmware naming module parameter */
38static char fw_filename_param[256] = DEFAULT_FW_FILE;
39/* As the remoteproc is setup at probe, just allow the filename readonly */
40module_param_string(filename, fw_filename_param, sizeof(fw_filename_param),
41 0444);
42MODULE_PARM_DESC(filename,
43 "Filename for firmware image for Ethos-U remoteproc");
44
45static bool auto_boot = DEFAULT_AUTO_BOOT;
46module_param(auto_boot, bool, DEFAULT_AUTO_BOOT);
47MODULE_PARM_DESC(auto_boot, "Set to one to auto boot at load.");
48
49struct ethosu_rproc {
50 struct device *dev;
51 struct reset_control *rstc;
52 struct rproc_mem_mapping *map;
53 size_t map_size;
54};
55
56struct rproc_mem_mapping {
57 const char *name;
58 phys_addr_t rproc_addr;
59 void __iomem *vaddr;
60 size_t size;
61};
62
63struct ethosu_rproc_config {
64 struct fw_config *fw;
65};
66
67/*****************************************************************************/
68
69static int ethosu_rproc_start(struct rproc *rproc)
70{
71 struct ethosu_rproc *ethosu = (struct ethosu_rproc *)rproc->priv;
72 struct device *dev = ethosu->dev;
73
74 dev_info(dev, "Starting up Ethos-U subsystem CPU!");
75
76 return reset_control_deassert(ethosu->rstc);
77}
78
79static int ethosu_rproc_stop(struct rproc *rproc)
80{
81 struct ethosu_rproc *ethosu = (struct ethosu_rproc *)rproc->priv;
82 struct device *dev = ethosu->dev;
83
84 dev_info(dev, "Stopping Ethos-U subsystem CPU!");
85
86 return reset_control_assert(ethosu->rstc);
87}
88
89static void ethosu_rproc_kick(struct rproc *rproc,
90 int vqid)
91{
92 return;
93}
94
95static void *ethosu_da_to_va(struct rproc *rproc,
96 u64 da,
97 int len)
98{
99 struct ethosu_rproc *ethosu = (struct ethosu_rproc *)rproc->priv;
100 int offset;
101 int i;
102
103 for (i = 0; i < ethosu->map_size; i++)
104 if (da >= ethosu->map[i].rproc_addr &&
105 da < (ethosu->map[i].rproc_addr + ethosu->map[i].size)) {
106 offset = da - ethosu->map[i].rproc_addr;
107 dev_info(ethosu->dev,
108 "mapping %llx to %p (offset: 0x%x)", da,
109 (void *)(ethosu->map[i].vaddr + offset),
110 offset);
111
112 return (void *)(ethosu->map[i].vaddr + offset);
113 }
114
115 return NULL;
116}
117
118static const struct rproc_ops ethosu_rproc_ops = {
119 .start = &ethosu_rproc_start,
120 .stop = &ethosu_rproc_stop,
121 .kick = &ethosu_rproc_kick,
122 .da_to_va = &ethosu_da_to_va,
123};
124
125/**
126 * Since the remote side doesn't yet support rpmsg just return an
127 * empty resource table when asked about it.
128 */
129struct resource_table *ethosu_rproc_find_rsc_table(struct rproc *rproc,
130 const struct firmware *fw,
131 int *tablesz)
132{
133 static struct resource_table table = { .ver = 1, };
134 struct ethosu_rproc *ethosu = (struct ethosu_rproc *)rproc->priv;
135
136 dev_info(ethosu->dev, "Sizeof struct resource_table : %zu",
137 sizeof(table));
138 *tablesz = sizeof(table);
139
140 return &table;
141}
142
143/*****************************************************************************/
144
145static int ethosu_rproc_of_memory_translations(struct platform_device *pdev,
146 struct ethosu_rproc *ethosu_rproc)
147{
148 const char *const of_rproc_address_cells =
149 "#ethosu,rproc-address-cells";
150 const char *const of_rproc_ranges = "ethosu,rproc-ranges";
151 const char *const of_rproc_ranges_names = "ethosu,rproc-names";
152
153 struct device *dev = &pdev->dev;
154 struct device_node *np = dev->of_node;
155 struct rproc_mem_mapping *mem_map;
156 const __be32 *rproc_ranges;
157
158 int addr_cells, rproc_addr_cells, size_cells, cells_for_array_element;
159 int i, len, cnt, name_cnt, ret = 0;
160
161 if (of_property_read_u32(np, of_rproc_address_cells,
162 &rproc_addr_cells)) {
163 dev_info(dev, "%s not defined in dtb", of_rproc_address_cells);
164
165 return -ENODEV;
166 }
167
168 addr_cells = of_n_addr_cells(np);
169 size_cells = of_n_size_cells(np);
170
171 dev_dbg(dev, "Using %d remote proc address cells for parsing mapping",
172 rproc_addr_cells);
173 dev_dbg(dev,
174 "Using %d of size %d parent address cells for parsing mapping",
175 addr_cells, size_cells);
176
177 cells_for_array_element = addr_cells + rproc_addr_cells + size_cells;
178
179 cnt = of_property_count_elems_of_size(np, of_rproc_ranges,
180 cells_for_array_element);
181 cnt /= sizeof(u32);
182
183 if (cnt <= 0) {
184 dev_info(dev, "No remoteproc memory mapping ranges found.");
185
186 return 0;
187 }
188
189 name_cnt = of_property_count_strings(np, of_rproc_ranges_names);
190 if (name_cnt > 0 && name_cnt != cnt) {
191 dev_err(dev, "Mismatch length for %s and %s", of_rproc_ranges,
192 of_rproc_ranges_names);
193
194 return -EINVAL;
195 }
196
197 mem_map = devm_kcalloc(dev, cnt, sizeof(*mem_map), GFP_KERNEL);
198 if (!mem_map)
199 return -ENOMEM;
200
201 rproc_ranges = of_get_property(np, of_rproc_ranges, &len);
202
203 for (i = 0; i < cnt; i++) {
204 struct resource *r;
205 const char *name = NULL;
206 int n;
207
208 of_property_read_string_index(np, of_rproc_ranges_names, i,
209 &name);
210 mem_map[i].name = name;
211 n = i * cells_for_array_element;
212 mem_map[i].rproc_addr =
213 of_read_number(&rproc_ranges[n + addr_cells],
214 rproc_addr_cells);
215 mem_map[i].size =
216 of_read_number(&rproc_ranges[n + addr_cells +
217 rproc_addr_cells],
218 size_cells);
219
220 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
221 if (!r) {
222 dev_err(&pdev->dev, "Failed to get '%s' resource.\n",
223 name);
224
225 return -EINVAL;
226 }
227
228 mem_map[i].vaddr = devm_ioremap_wc(dev, r->start,
229 mem_map[i].size);
230 if (IS_ERR(mem_map[i].vaddr)) {
231 dev_err(dev, "Failed to remap '%s'", name);
232
233 return PTR_ERR(mem_map[i].vaddr);
234 }
235
236 dev_dbg(dev,
237 "rproc memory mapping[%i]=%s: da %llx, va, %pa, size %zx:\n",
238 i, name, mem_map[i].rproc_addr, &mem_map[i].vaddr,
239 mem_map[i].size);
240 }
241
242 ethosu_rproc->map = mem_map;
243 ethosu_rproc->map_size = cnt;
244 dev_dbg(dev, "rproc memory mapped %zx regions", ethosu_rproc->map_size);
245
246 return ret;
247}
248
249static const struct of_device_id ethosu_rproc_match[] = {
250 { .compatible = "arm,ethosu-sgm775-rproc" },
251};
252
253static int ethosu_rproc_probe(struct platform_device *pdev)
254{
255 struct device *dev = &pdev->dev;
256 struct device_node *np = dev->of_node;
257 struct ethosu_rproc *ethosu_rproc;
258 struct rproc *rproc;
259 int ret = -ENODEV;
260
261 rproc = rproc_alloc(dev, np->name, &ethosu_rproc_ops,
262 fw_filename_param,
263 sizeof(*ethosu_rproc));
264 if (!rproc) {
265 ret = -ENOMEM;
266 goto out;
267 }
268
269 /* Configure rproc */
270 rproc->has_iommu = false;
271 rproc->auto_boot = auto_boot;
272
273 platform_set_drvdata(pdev, rproc);
274
275 ethosu_rproc = rproc->priv;
276 ethosu_rproc->dev = dev;
277
278 /* Get the reset handler for the subsystem */
279 ethosu_rproc->rstc = devm_reset_control_get_exclusive_by_index(dev, 0);
280 if (IS_ERR(ethosu_rproc->rstc)) {
281 dev_err(&pdev->dev, "Failed to get reset controller.\n");
282 ret = PTR_ERR(ethosu_rproc->rstc);
283 goto free_rproc;
284 }
285
286 /* Get the translation from device memory to kernel space */
287 ret = ethosu_rproc_of_memory_translations(pdev, ethosu_rproc);
288 if (ret)
289 goto free_rproc;
290
291 ret = rproc_add(rproc);
292
293free_rproc:
294 if (ret)
295 rproc_free(rproc);
296
297out:
298
299 return ret;
300}
301
302static int ethosu_rproc_remove(struct platform_device *pdev)
303{
304 struct rproc *rproc = platform_get_drvdata(pdev);
305
306 rproc_del(rproc);
307 rproc_free(rproc);
308
309 return 0;
310}
311
312static struct platform_driver ethosu_rproc_driver = {
313 .probe = ethosu_rproc_probe,
314 .remove = ethosu_rproc_remove,
315 .driver = {
316 .name = "ethosu-rproc",
317 .of_match_table = of_match_ptr(ethosu_rproc_match),
318 },
319};
320
321module_platform_driver(ethosu_rproc_driver);
322
323MODULE_LICENSE("GPL v2");
324MODULE_AUTHOR("Arm Ltd");
325MODULE_DESCRIPTION("Arm Ethos-U NPU RemoteProc Driver");
326MODULE_VERSION(ETHOSU_RPROC_DRIVER_VERSION);