diff options
Diffstat (limited to 'remoteproc')
-rw-r--r-- | remoteproc/ethosu_remoteproc.c | 145 |
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 = ðosu_rproc_prepare, - .start = ðosu_rproc_start, - .stop = ðosu_rproc_stop, - .kick = ðosu_rproc_kick, + .prepare = ðosu_rproc_prepare, + .start = ðosu_rproc_start, + .stop = ðosu_rproc_stop, + .kick = ðosu_rproc_kick, + .handle_rsc = ðosu_rproc_handle_rsc, }; static int ethosu_mailbox_init(struct ethosu_rproc *erproc) |