blob: b1f879349cfae6f2180d19d7fa8cb121097e4c9d [file] [log] [blame]
Per Åstrand2cd53972021-04-12 13:46:04 +02001/*
Kristofer Jonssona70bfde2023-01-12 10:00:03 +01002 * Copyright 2021-2023 Arm Limited and/or its affiliates
Per Åstrand2cd53972021-04-12 13:46:04 +02003 *
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 */
Kristofer Jonssona70bfde2023-01-12 10:00:03 +010020#include <linux/dma-mapping.h>
Per Åstrand2cd53972021-04-12 13:46:04 +020021#include <linux/firmware.h>
22#include <linux/io.h>
Kristofer Jonssona70bfde2023-01-12 10:00:03 +010023#include <linux/irqreturn.h>
Per Åstrand2cd53972021-04-12 13:46:04 +020024#include <linux/kernel.h>
Kristofer Jonssona70bfde2023-01-12 10:00:03 +010025#include <linux/mailbox_client.h>
Per Åstrand2cd53972021-04-12 13:46:04 +020026#include <linux/module.h>
27#include <linux/of.h>
28#include <linux/of_address.h>
29#include <linux/of_device.h>
Kristofer Jonssona70bfde2023-01-12 10:00:03 +010030#include <linux/of_reserved_mem.h>
Per Åstrand2cd53972021-04-12 13:46:04 +020031#include <linux/platform_device.h>
32#include <linux/remoteproc.h>
33#include <linux/reset.h>
Nir Ekhauz48239212021-11-23 10:28:34 +020034#include <linux/version.h>
Kristofer Jonssona70bfde2023-01-12 10:00:03 +010035#include <linux/workqueue.h>
36
37/****************************************************************************
38 * Defines
39 ****************************************************************************/
40
41#define DMA_ADDR_BITS 32 /* Number of address bits */
Per Åstrand2cd53972021-04-12 13:46:04 +020042
43#define ETHOSU_RPROC_DRIVER_VERSION "0.0.1"
44
45#define DEFAULT_FW_FILE "arm-ethos-u65.fw"
Kristofer Jonssona70bfde2023-01-12 10:00:03 +010046#define DEFAULT_AUTO_BOOT false
Per Åstrand2cd53972021-04-12 13:46:04 +020047
48/* firmware naming module parameter */
49static char fw_filename_param[256] = DEFAULT_FW_FILE;
Kristofer Jonssona70bfde2023-01-12 10:00:03 +010050
Per Åstrand2cd53972021-04-12 13:46:04 +020051/* As the remoteproc is setup at probe, just allow the filename readonly */
52module_param_string(filename, fw_filename_param, sizeof(fw_filename_param),
53 0444);
54MODULE_PARM_DESC(filename,
55 "Filename for firmware image for Ethos-U remoteproc");
56
57static bool auto_boot = DEFAULT_AUTO_BOOT;
Kristofer Jonssona70bfde2023-01-12 10:00:03 +010058module_param(auto_boot, bool, 0);
Per Åstrand2cd53972021-04-12 13:46:04 +020059MODULE_PARM_DESC(auto_boot, "Set to one to auto boot at load.");
60
61struct ethosu_rproc {
Kristofer Jonssona70bfde2023-01-12 10:00:03 +010062 struct device *dev;
63 struct reset_control *rstc;
64 struct mbox_client mbox_client;
65 struct mbox_chan *ch_rx;
66 struct mbox_chan *ch_tx;
67 struct workqueue_struct *wq;
68 struct work_struct work;
Per Åstrand2cd53972021-04-12 13:46:04 +020069};
70
Kristofer Jonssona70bfde2023-01-12 10:00:03 +010071/* declaration is in remoteproc_internal.h */
72extern irqreturn_t rproc_vq_interrupt(struct rproc *rproc,
73 int vq_id);
Per Åstrand2cd53972021-04-12 13:46:04 +020074
Kristofer Jonssona70bfde2023-01-12 10:00:03 +010075static void ethosu_mbox_bottom(struct work_struct *work)
76{
77 struct ethosu_rproc *erproc = container_of(
78 work, struct ethosu_rproc, work);
79 struct rproc *rproc = dev_get_drvdata(erproc->dev);
Per Åstrand2cd53972021-04-12 13:46:04 +020080
Kristofer Jonssona70bfde2023-01-12 10:00:03 +010081 dev_dbg(&rproc->dev, "Handle interrupt");
82
83 rproc_vq_interrupt(rproc, 0);
84}
85
86static void ethosu_mbox_top(struct mbox_client *client,
87 void *message)
88{
89 struct ethosu_rproc *erproc = container_of(
90 client, struct ethosu_rproc, mbox_client);
91
92 queue_work(erproc->wq, &erproc->work);
93}
94
95static dma_addr_t ethosu_of_pa_to_da(struct rproc *rproc,
96 const phys_addr_t pa,
97 const size_t size)
98{
99 static const char of_rproc_ranges[] = "ethosu,dma-ranges";
100
101 struct device *dev = rproc->dev.parent;
102 struct device_node *np = dev->of_node;
103 const __be32 *rproc_ranges = of_get_property(np, of_rproc_ranges, NULL);
104 const int addr_cells = of_n_addr_cells(np);
105 const int size_cells = of_n_size_cells(np);
106 const int ranges_cells = addr_cells + addr_cells + size_cells;
107 int ranges_cnt;
108 int i;
109
110 ranges_cnt = of_property_count_elems_of_size(
111 np, of_rproc_ranges, ranges_cells * sizeof(u32));
112
113 for (i = 0; i < ranges_cnt; i++) {
114 const int offset = i * ranges_cells;
115
116 const uint64_t of_da = of_read_number(
117 &rproc_ranges[offset], addr_cells);
118 const uint64_t of_pa = of_read_number(
119 &rproc_ranges[offset + addr_cells], addr_cells);
120 const uint64_t of_size = of_read_number(
121 &rproc_ranges[offset + addr_cells + addr_cells],
122 size_cells);
123
124 if (pa >= of_pa && (pa + size) <= (of_pa + of_size)) {
125 const dma_addr_t da = of_da + pa - of_pa;
126
127 dev_dbg(dev, "PA to DA. pa=0x%llx, da=0x%llx", pa, da);
128
129 return da;
130 }
131 }
132
133 return (dma_addr_t)(-1);
134}
135
136static int ethosu_add_carveout(struct rproc *rproc,
137 const phys_addr_t pa,
138 const size_t size,
139 const char *name)
140{
141 struct device *dev = rproc->dev.parent;
142 dma_addr_t da;
143 void __iomem *va;
144 struct rproc_mem_entry *mem;
145
146 da = ethosu_of_pa_to_da(rproc, pa, size);
147 if (da == (dma_addr_t)(-1)) {
148 dev_err(dev, "No mapping found for PA. pa=%llx, size=%zu", pa,
149 size);
150
151 return -ENOMEM;
152 }
153
154 va = devm_ioremap_wc(dev, pa, size);
155 if (!va) {
156 dev_err(dev, "Failed to remap address. pa=%llx, len=%zu", pa,
157 size);
158
159 return -ENOMEM;
160 }
161
162 mem = rproc_mem_entry_init(dev, va, pa, size, da, NULL, NULL, name);
163 if (!mem)
164 return -ENOMEM;
165
166 dev_info(dev, "Add carveout mapping. dma=%llx, da=%x, va=%p, len=%zu",
167 mem->dma, mem->da, mem->va, mem->len);
168
169 rproc_add_carveout(rproc, mem);
170
171 return 0;
172}
173
174static int ethosu_rproc_prepare(struct rproc *rproc)
175{
176 struct device *dev = rproc->dev.parent;
177 struct device_node *np = dev->of_node;
178 struct of_phandle_iterator it;
179 struct resource res;
180 int i;
181 int ret;
182
183 dev_info(dev, "Preparing Ethos-U");
184
185 /* Add carveout for each 'reg' device tree entry */
186 for (i = 0; of_address_to_resource(np, i, &res) == 0; i++) {
187 dev_info(dev, "Found resource. start=%llx, size=%llx",
188 res.start, resource_size(&res));
189
190 ret = ethosu_add_carveout(rproc, res.start,
191 resource_size(&res), res.name);
192 if (ret)
193 return ret;
194 }
195
196 of_phandle_iterator_init(&it, np, "memory-region", NULL, 0);
197 while (of_phandle_iterator_next(&it) == 0) {
198 struct reserved_mem *res_mem = of_reserved_mem_lookup(it.node);
199
200 if (!res_mem) {
201 dev_err(dev, "Failed to look up memory region. node=%p",
202 it.node);
203
204 return -EINVAL;
205 }
206
207 dev_info(dev,
208 "Found memory region. pa=%llx, size=%llu, name=%s",
209 res_mem->base, res_mem->size, it.node->name);
210
211 ret = ethosu_add_carveout(rproc, res_mem->base, res_mem->size,
212 it.node->name);
213 if (ret)
214 return ret;
215 }
216
217 return 0;
218}
Per Åstrand2cd53972021-04-12 13:46:04 +0200219
220static int ethosu_rproc_start(struct rproc *rproc)
221{
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100222 struct ethosu_rproc *erproc = (struct ethosu_rproc *)rproc->priv;
223 struct device *dev = erproc->dev;
Per Åstrand2cd53972021-04-12 13:46:04 +0200224
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100225 dev_info(dev, "Starting up Ethos-U subsystem CPU");
Per Åstrand2cd53972021-04-12 13:46:04 +0200226
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100227 return reset_control_deassert(erproc->rstc);
Per Åstrand2cd53972021-04-12 13:46:04 +0200228}
229
230static int ethosu_rproc_stop(struct rproc *rproc)
231{
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100232 struct ethosu_rproc *erproc = (struct ethosu_rproc *)rproc->priv;
233 struct device *dev = erproc->dev;
Per Åstrand2cd53972021-04-12 13:46:04 +0200234
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100235 dev_info(dev, "Stopping Ethos-U subsystem CPU");
Per Åstrand2cd53972021-04-12 13:46:04 +0200236
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100237 return reset_control_assert(erproc->rstc);
Per Åstrand2cd53972021-04-12 13:46:04 +0200238}
239
240static void ethosu_rproc_kick(struct rproc *rproc,
241 int vqid)
242{
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100243 struct ethosu_rproc *erproc = (struct ethosu_rproc *)rproc->priv;
Per Åstrand2cd53972021-04-12 13:46:04 +0200244
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100245 dev_dbg(&rproc->dev, "Kicking Ethos-U remoteproc vqid: %d!", vqid);
Per Åstrand2cd53972021-04-12 13:46:04 +0200246
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100247 mbox_send_message(erproc->ch_tx, (void *)&vqid);
Per Åstrand2cd53972021-04-12 13:46:04 +0200248}
249
250static const struct rproc_ops ethosu_rproc_ops = {
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100251 .prepare = &ethosu_rproc_prepare,
252 .start = &ethosu_rproc_start,
253 .stop = &ethosu_rproc_stop,
254 .kick = &ethosu_rproc_kick,
Per Åstrand2cd53972021-04-12 13:46:04 +0200255};
256
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100257static int ethosu_mailbox_init(struct ethosu_rproc *erproc)
Per Åstrand2cd53972021-04-12 13:46:04 +0200258{
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100259 struct device *dev = erproc->dev;
260 struct mbox_client *cl = &erproc->mbox_client;
Per Åstrand2cd53972021-04-12 13:46:04 +0200261
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100262 INIT_WORK(&erproc->work, ethosu_mbox_bottom);
Per Åstrand2cd53972021-04-12 13:46:04 +0200263
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100264 erproc->wq = create_singlethread_workqueue("ethosu_rproc_wq");
265 if (!erproc->wq) {
266 dev_err(dev, "Failed to create work queue");
Per Åstrand2cd53972021-04-12 13:46:04 +0200267
268 return -EINVAL;
269 }
270
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100271 cl->dev = dev;
272 cl->rx_callback = ethosu_mbox_top;
273 cl->tx_prepare = NULL;
274 cl->tx_done = NULL;
275 cl->tx_block = true;
276 cl->knows_txdone = false;
277 cl->tx_tout = 500;
Per Åstrand2cd53972021-04-12 13:46:04 +0200278
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100279 erproc->ch_rx = mbox_request_channel_byname(cl, "rx");
280 if (IS_ERR(erproc->ch_rx)) {
281 dev_err(dev, "Failed to request mbox chan rx");
Per Åstrand2cd53972021-04-12 13:46:04 +0200282
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100283 return PTR_ERR(erproc->ch_rx);
Per Åstrand2cd53972021-04-12 13:46:04 +0200284 }
285
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100286 erproc->ch_tx = mbox_request_channel_byname(cl, "tx");
287 if (IS_ERR(erproc->ch_tx)) {
288 dev_info(dev, "Using same channel for RX and TX");
289 erproc->ch_tx = erproc->ch_rx;
290 }
Per Åstrand2cd53972021-04-12 13:46:04 +0200291
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100292 return 0;
Per Åstrand2cd53972021-04-12 13:46:04 +0200293}
294
295static const struct of_device_id ethosu_rproc_match[] = {
Per Åstrand9f36f2e2021-09-30 09:57:34 +0200296 { .compatible = "arm,ethosu-rproc" },
Per Åstrandb9248a42022-05-18 16:05:16 +0200297 { /* sentinel */ },
Per Åstrand2cd53972021-04-12 13:46:04 +0200298};
299
300static int ethosu_rproc_probe(struct platform_device *pdev)
301{
302 struct device *dev = &pdev->dev;
303 struct device_node *np = dev->of_node;
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100304 struct ethosu_rproc *erproc;
Per Åstrand2cd53972021-04-12 13:46:04 +0200305 struct rproc *rproc;
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100306 int ret;
Per Åstrand2cd53972021-04-12 13:46:04 +0200307
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100308 /* map the first 'memory-region' for DMA-mapping */
309 ret = of_reserved_mem_device_init(dev);
310 if (ret)
311 return ret;
312
313 dma_set_mask_and_coherent(dev, DMA_BIT_MASK(DMA_ADDR_BITS));
314
315 rproc = devm_rproc_alloc(dev, np->name, &ethosu_rproc_ops,
316 fw_filename_param,
317 sizeof(*erproc));
318 if (!rproc)
319 return -ENOMEM;
320
321 platform_set_drvdata(pdev, rproc);
Per Åstrand2cd53972021-04-12 13:46:04 +0200322
323 /* Configure rproc */
324 rproc->has_iommu = false;
325 rproc->auto_boot = auto_boot;
326
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100327 /* Configure Ethos-U rproc */
328 erproc = rproc->priv;
329 erproc->dev = dev;
Per Åstrand2cd53972021-04-12 13:46:04 +0200330
331 /* Get the reset handler for the subsystem */
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100332 erproc->rstc = devm_reset_control_get_exclusive_by_index(dev, 0);
333 if (IS_ERR(erproc->rstc)) {
334 dev_err(&pdev->dev, "Failed to get reset controller.");
335
336 return PTR_ERR(erproc->rstc);
Per Åstrand2cd53972021-04-12 13:46:04 +0200337 }
338
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100339 /* Allocate and initialize mailbox client */
340 ret = ethosu_mailbox_init(erproc);
Per Åstrand2cd53972021-04-12 13:46:04 +0200341 if (ret)
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100342 return ret;
Per Åstrand2cd53972021-04-12 13:46:04 +0200343
344 ret = rproc_add(rproc);
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100345 if (ret) {
346 dev_err(dev, "Failed to add rproc");
347 goto free_mbox;
348 }
Per Åstrand2cd53972021-04-12 13:46:04 +0200349
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100350 return 0;
Per Åstrand2cd53972021-04-12 13:46:04 +0200351
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100352free_mbox:
353 if (erproc->wq)
354 destroy_workqueue(erproc->wq);
355
356 mbox_free_channel(erproc->ch_rx);
357
358 if (erproc->ch_tx != erproc->ch_rx)
359 mbox_free_channel(erproc->ch_tx);
Per Åstrand2cd53972021-04-12 13:46:04 +0200360
361 return ret;
362}
363
364static int ethosu_rproc_remove(struct platform_device *pdev)
365{
366 struct rproc *rproc = platform_get_drvdata(pdev);
Kristofer Jonssona70bfde2023-01-12 10:00:03 +0100367 struct ethosu_rproc *erproc = rproc->priv;
368
369 if (erproc->wq)
370 destroy_workqueue(erproc->wq);
371
372 if (erproc->ch_tx != erproc->ch_rx)
373 mbox_free_channel(erproc->ch_tx);
374
375 mbox_free_channel(erproc->ch_rx);
Per Åstrand2cd53972021-04-12 13:46:04 +0200376
377 rproc_del(rproc);
Per Åstrand2cd53972021-04-12 13:46:04 +0200378
379 return 0;
380}
381
382static struct platform_driver ethosu_rproc_driver = {
383 .probe = ethosu_rproc_probe,
384 .remove = ethosu_rproc_remove,
385 .driver = {
386 .name = "ethosu-rproc",
387 .of_match_table = of_match_ptr(ethosu_rproc_match),
388 },
389};
390
391module_platform_driver(ethosu_rproc_driver);
392
393MODULE_LICENSE("GPL v2");
394MODULE_AUTHOR("Arm Ltd");
395MODULE_DESCRIPTION("Arm Ethos-U NPU RemoteProc Driver");
396MODULE_VERSION(ETHOSU_RPROC_DRIVER_VERSION);