aboutsummaryrefslogtreecommitdiff
path: root/remoteproc/ethosu_remoteproc.c
diff options
context:
space:
mode:
Diffstat (limited to 'remoteproc/ethosu_remoteproc.c')
-rw-r--r--remoteproc/ethosu_remoteproc.c145
1 files changed, 91 insertions, 54 deletions
diff --git a/remoteproc/ethosu_remoteproc.c b/remoteproc/ethosu_remoteproc.c
index b1f8793..0369156 100644
--- a/remoteproc/ethosu_remoteproc.c
+++ b/remoteproc/ethosu_remoteproc.c
@@ -1,5 +1,6 @@
/*
- * Copyright 2021-2023 Arm Limited and/or its affiliates
+ * SPDX-FileCopyrightText: Copyright 2021-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * SPDX-License-Identifier: GPL-2.0-only
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@@ -14,10 +15,10 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
- *
- * SPDX-License-Identifier: GPL-2.0-only
*/
+
#include <linux/dma-mapping.h>
+#include <linux/dma-direct.h>
#include <linux/firmware.h>
#include <linux/io.h>
#include <linux/irqreturn.h>
@@ -58,6 +59,35 @@ static bool auto_boot = DEFAULT_AUTO_BOOT;
module_param(auto_boot, bool, 0);
MODULE_PARM_DESC(auto_boot, "Set to one to auto boot at load.");
+#define RSC_MAPPING RSC_VENDOR_START + 1
+
+/**
+ * struct fw_rsc_map_range - memory map range
+ * @da: Start device address of the memory address range
+ * @pa: Start physical address of the memory address range
+ * @len: length of memory address range
+ *
+ * Memory range to translate between physical and device addresses.
+ */
+struct fw_rsc_map_range {
+ uint32_t da;
+ uint32_t pa;
+ uint32_t len;
+} __packed;
+
+/**
+ * struct fw_rsc_mapping - memory map for address translation
+ * @num_ranges: Number of ranges in the memory map
+ * @range: Array of the ranges in the memory map
+ *
+ * This resource entry requests the host to provide information for how to
+ * translate between physical and device addresses.
+ */
+struct fw_rsc_mapping {
+ uint8_t num_ranges;
+ struct fw_rsc_map_range range[0];
+} __packed;
+
struct ethosu_rproc {
struct device *dev;
struct reset_control *rstc;
@@ -92,47 +122,6 @@ static void ethosu_mbox_top(struct mbox_client *client,
queue_work(erproc->wq, &erproc->work);
}
-static dma_addr_t ethosu_of_pa_to_da(struct rproc *rproc,
- const phys_addr_t pa,
- const size_t size)
-{
- static const char of_rproc_ranges[] = "ethosu,dma-ranges";
-
- struct device *dev = rproc->dev.parent;
- struct device_node *np = dev->of_node;
- const __be32 *rproc_ranges = of_get_property(np, of_rproc_ranges, NULL);
- const int addr_cells = of_n_addr_cells(np);
- const int size_cells = of_n_size_cells(np);
- const int ranges_cells = addr_cells + addr_cells + size_cells;
- int ranges_cnt;
- int i;
-
- ranges_cnt = of_property_count_elems_of_size(
- np, of_rproc_ranges, ranges_cells * sizeof(u32));
-
- for (i = 0; i < ranges_cnt; i++) {
- const int offset = i * ranges_cells;
-
- const uint64_t of_da = of_read_number(
- &rproc_ranges[offset], addr_cells);
- const uint64_t of_pa = of_read_number(
- &rproc_ranges[offset + addr_cells], addr_cells);
- const uint64_t of_size = of_read_number(
- &rproc_ranges[offset + addr_cells + addr_cells],
- size_cells);
-
- if (pa >= of_pa && (pa + size) <= (of_pa + of_size)) {
- const dma_addr_t da = of_da + pa - of_pa;
-
- dev_dbg(dev, "PA to DA. pa=0x%llx, da=0x%llx", pa, da);
-
- return da;
- }
- }
-
- return (dma_addr_t)(-1);
-}
-
static int ethosu_add_carveout(struct rproc *rproc,
const phys_addr_t pa,
const size_t size,
@@ -143,9 +132,10 @@ static int ethosu_add_carveout(struct rproc *rproc,
void __iomem *va;
struct rproc_mem_entry *mem;
- da = ethosu_of_pa_to_da(rproc, pa, size);
- if (da == (dma_addr_t)(-1)) {
- dev_err(dev, "No mapping found for PA. pa=%llx, size=%zu", pa,
+ da = translate_phys_to_dma(dev, pa);
+ dev_dbg(dev, "PA to DA. pa=0x%pa, da=0x%pad", &pa, &da);
+ if (da == DMA_MAPPING_ERROR) {
+ dev_err(dev, "No mapping found for PA. pa=%pa, size=%zu", &pa,
size);
return -ENOMEM;
@@ -153,7 +143,7 @@ static int ethosu_add_carveout(struct rproc *rproc,
va = devm_ioremap_wc(dev, pa, size);
if (!va) {
- dev_err(dev, "Failed to remap address. pa=%llx, len=%zu", pa,
+ dev_err(dev, "Failed to remap address. pa=%pa, len=%zu", &pa,
size);
return -ENOMEM;
@@ -163,8 +153,8 @@ static int ethosu_add_carveout(struct rproc *rproc,
if (!mem)
return -ENOMEM;
- dev_info(dev, "Add carveout mapping. dma=%llx, da=%x, va=%p, len=%zu",
- mem->dma, mem->da, mem->va, mem->len);
+ dev_info(dev, "Add carveout mapping. dma=%pad, da=%x, va=%p, len=%zu",
+ &mem->dma, mem->da, mem->va, mem->len);
rproc_add_carveout(rproc, mem);
@@ -247,11 +237,58 @@ static void ethosu_rproc_kick(struct rproc *rproc,
mbox_send_message(erproc->ch_tx, (void *)&vqid);
}
+static int ethosu_rproc_handle_rsc(struct rproc *rproc,
+ u32 rsc_type,
+ void *rsc,
+ int offset,
+ int avail)
+{
+ struct ethosu_rproc *erproc = (struct ethosu_rproc *)rproc->priv;
+ struct device *dev = erproc->dev;
+ struct fw_rsc_mapping *mapping = rsc;
+ const struct bus_dma_region *map;
+ size_t num_ranges = 0U;
+ size_t i;
+
+ if (rsc_type != RSC_MAPPING)
+ return RSC_IGNORED;
+
+ if (struct_size(mapping, range, mapping->num_ranges) > avail) {
+ dev_err(dev, "mapping rsc is truncated\n");
+
+ return -EINVAL;
+ }
+
+ for (map = dev->dma_range_map; map->size; ++map)
+ num_ranges++;
+
+ if (num_ranges > mapping->num_ranges) {
+ dev_err(dev,
+ "Mapping rsc doesn't have enough room for DMA ranges\n");
+
+ return -EINVAL;
+ }
+
+ for (i = 0U; i < num_ranges; ++i) {
+ map = &dev->dma_range_map[i];
+ struct fw_rsc_map_range *range = &mapping->range[i];
+
+ range->da = map->dma_start;
+ range->pa = map->cpu_start;
+ range->len = map->size;
+ }
+
+ dev_dbg(dev, "handle_rsc: Mapping rsc setup");
+
+ return RSC_HANDLED;
+}
+
static const struct rproc_ops ethosu_rproc_ops = {
- .prepare = &ethosu_rproc_prepare,
- .start = &ethosu_rproc_start,
- .stop = &ethosu_rproc_stop,
- .kick = &ethosu_rproc_kick,
+ .prepare = &ethosu_rproc_prepare,
+ .start = &ethosu_rproc_start,
+ .stop = &ethosu_rproc_stop,
+ .kick = &ethosu_rproc_kick,
+ .handle_rsc = &ethosu_rproc_handle_rsc,
};
static int ethosu_mailbox_init(struct ethosu_rproc *erproc)