Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 1 | /* |
Mikael Olsson | 4bfd987 | 2024-04-16 16:36:47 +0200 | [diff] [blame] | 2 | * SPDX-FileCopyrightText: Copyright 2021-2024 Arm Limited and/or its affiliates <open-source-office@arm.com> |
Mikael Olsson | 9d0ea8b | 2023-06-05 16:16:36 +0200 | [diff] [blame] | 3 | * SPDX-License-Identifier: GPL-2.0-only |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 4 | * |
| 5 | * This program is free software and is provided to you under the terms of the |
| 6 | * GNU General Public License version 2 as published by the Free Software |
| 7 | * Foundation, and any use by you of this program is subject to the terms |
| 8 | * of such GNU licence. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, you can access it online at |
| 17 | * http://www.gnu.org/licenses/gpl-2.0.html. |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 18 | */ |
Mikael Olsson | 9d0ea8b | 2023-06-05 16:16:36 +0200 | [diff] [blame] | 19 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 20 | #include <linux/dma-mapping.h> |
Mikael Olsson | 9d0ea8b | 2023-06-05 16:16:36 +0200 | [diff] [blame] | 21 | #include <linux/dma-direct.h> |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 22 | #include <linux/firmware.h> |
| 23 | #include <linux/io.h> |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 24 | #include <linux/irqreturn.h> |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 25 | #include <linux/kernel.h> |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 26 | #include <linux/mailbox_client.h> |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 27 | #include <linux/module.h> |
| 28 | #include <linux/of.h> |
| 29 | #include <linux/of_address.h> |
| 30 | #include <linux/of_device.h> |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 31 | #include <linux/of_reserved_mem.h> |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 32 | #include <linux/platform_device.h> |
| 33 | #include <linux/remoteproc.h> |
| 34 | #include <linux/reset.h> |
Nir Ekhauz | 4823921 | 2021-11-23 10:28:34 +0200 | [diff] [blame] | 35 | #include <linux/version.h> |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 36 | #include <linux/workqueue.h> |
| 37 | |
| 38 | /**************************************************************************** |
| 39 | * Defines |
| 40 | ****************************************************************************/ |
| 41 | |
| 42 | #define DMA_ADDR_BITS 32 /* Number of address bits */ |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 43 | |
| 44 | #define ETHOSU_RPROC_DRIVER_VERSION "0.0.1" |
| 45 | |
| 46 | #define DEFAULT_FW_FILE "arm-ethos-u65.fw" |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 47 | #define DEFAULT_AUTO_BOOT false |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 48 | |
| 49 | /* firmware naming module parameter */ |
| 50 | static char fw_filename_param[256] = DEFAULT_FW_FILE; |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 51 | |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 52 | /* As the remoteproc is setup at probe, just allow the filename readonly */ |
| 53 | module_param_string(filename, fw_filename_param, sizeof(fw_filename_param), |
| 54 | 0444); |
| 55 | MODULE_PARM_DESC(filename, |
| 56 | "Filename for firmware image for Ethos-U remoteproc"); |
| 57 | |
| 58 | static bool auto_boot = DEFAULT_AUTO_BOOT; |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 59 | module_param(auto_boot, bool, 0); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 60 | MODULE_PARM_DESC(auto_boot, "Set to one to auto boot at load."); |
| 61 | |
Mikael Olsson | 9d0ea8b | 2023-06-05 16:16:36 +0200 | [diff] [blame] | 62 | #define RSC_MAPPING RSC_VENDOR_START + 1 |
| 63 | |
| 64 | /** |
| 65 | * struct fw_rsc_map_range - memory map range |
| 66 | * @da: Start device address of the memory address range |
| 67 | * @pa: Start physical address of the memory address range |
| 68 | * @len: length of memory address range |
| 69 | * |
| 70 | * Memory range to translate between physical and device addresses. |
| 71 | */ |
| 72 | struct fw_rsc_map_range { |
| 73 | uint32_t da; |
| 74 | uint32_t pa; |
| 75 | uint32_t len; |
| 76 | } __packed; |
| 77 | |
| 78 | /** |
| 79 | * struct fw_rsc_mapping - memory map for address translation |
| 80 | * @num_ranges: Number of ranges in the memory map |
| 81 | * @range: Array of the ranges in the memory map |
| 82 | * |
| 83 | * This resource entry requests the host to provide information for how to |
| 84 | * translate between physical and device addresses. |
| 85 | */ |
| 86 | struct fw_rsc_mapping { |
| 87 | uint8_t num_ranges; |
| 88 | struct fw_rsc_map_range range[0]; |
| 89 | } __packed; |
| 90 | |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 91 | struct ethosu_rproc { |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 92 | struct device *dev; |
| 93 | struct reset_control *rstc; |
| 94 | struct mbox_client mbox_client; |
| 95 | struct mbox_chan *ch_rx; |
| 96 | struct mbox_chan *ch_tx; |
| 97 | struct workqueue_struct *wq; |
| 98 | struct work_struct work; |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 99 | }; |
| 100 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 101 | /* declaration is in remoteproc_internal.h */ |
| 102 | extern irqreturn_t rproc_vq_interrupt(struct rproc *rproc, |
| 103 | int vq_id); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 104 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 105 | static void ethosu_mbox_bottom(struct work_struct *work) |
| 106 | { |
| 107 | struct ethosu_rproc *erproc = container_of( |
| 108 | work, struct ethosu_rproc, work); |
| 109 | struct rproc *rproc = dev_get_drvdata(erproc->dev); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 110 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 111 | dev_dbg(&rproc->dev, "Handle interrupt"); |
| 112 | |
| 113 | rproc_vq_interrupt(rproc, 0); |
| 114 | } |
| 115 | |
| 116 | static void ethosu_mbox_top(struct mbox_client *client, |
| 117 | void *message) |
| 118 | { |
| 119 | struct ethosu_rproc *erproc = container_of( |
| 120 | client, struct ethosu_rproc, mbox_client); |
| 121 | |
| 122 | queue_work(erproc->wq, &erproc->work); |
| 123 | } |
| 124 | |
Mikael Olsson | 9f176ba | 2023-11-10 15:15:34 +0100 | [diff] [blame] | 125 | static int ethosu_mem_alloc(struct rproc *rproc, |
| 126 | struct rproc_mem_entry *mem) |
| 127 | { |
| 128 | struct device *dev = rproc->dev.parent; |
| 129 | void *va; |
| 130 | |
Mikael Olsson | 4bfd987 | 2024-04-16 16:36:47 +0200 | [diff] [blame] | 131 | if (mem->is_iomem) |
| 132 | va = (__force void *)devm_ioremap(dev, mem->dma, mem->len); |
| 133 | else |
| 134 | va = devm_memremap(dev, mem->dma, mem->len, MEMREMAP_WC); |
| 135 | |
Mikael Olsson | 9f176ba | 2023-11-10 15:15:34 +0100 | [diff] [blame] | 136 | if (IS_ERR_OR_NULL(va)) { |
| 137 | dev_err(dev, "Failed to remap address. pa=%pa, len=%zu", |
| 138 | &mem->dma, |
| 139 | mem->len); |
| 140 | |
| 141 | return -ENOMEM; |
| 142 | } |
| 143 | |
| 144 | mem->va = va; |
Mikael Olsson | 9f176ba | 2023-11-10 15:15:34 +0100 | [diff] [blame] | 145 | |
| 146 | return 0; |
| 147 | } |
| 148 | |
| 149 | static int ethosu_mem_release(struct rproc *rproc, |
| 150 | struct rproc_mem_entry *mem) |
| 151 | { |
| 152 | struct device *dev = rproc->dev.parent; |
| 153 | |
Mikael Olsson | 4bfd987 | 2024-04-16 16:36:47 +0200 | [diff] [blame] | 154 | if (!mem->va) { |
| 155 | dev_warn(dev, |
| 156 | "Memory release. No mapping for memory %s pa=%p len=%zu", |
| 157 | mem->name, &mem->dma, mem->len); |
| 158 | goto done; |
| 159 | } |
| 160 | |
| 161 | if (mem->is_iomem) |
Mikael Olsson | 9f176ba | 2023-11-10 15:15:34 +0100 | [diff] [blame] | 162 | devm_iounmap(dev, (__force __iomem void *)mem->va); |
Mikael Olsson | 4bfd987 | 2024-04-16 16:36:47 +0200 | [diff] [blame] | 163 | else |
| 164 | devm_memunmap(dev, mem->va); |
| 165 | |
| 166 | done: |
Mikael Olsson | 9f176ba | 2023-11-10 15:15:34 +0100 | [diff] [blame] | 167 | |
| 168 | return 0; |
| 169 | } |
| 170 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 171 | static int ethosu_add_carveout(struct rproc *rproc, |
| 172 | const phys_addr_t pa, |
| 173 | const size_t size, |
Mikael Olsson | 4bfd987 | 2024-04-16 16:36:47 +0200 | [diff] [blame] | 174 | const char *name, |
| 175 | bool is_iomem) |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 176 | { |
| 177 | struct device *dev = rproc->dev.parent; |
| 178 | dma_addr_t da; |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 179 | struct rproc_mem_entry *mem; |
| 180 | |
Mikael Olsson | 9d0ea8b | 2023-06-05 16:16:36 +0200 | [diff] [blame] | 181 | da = translate_phys_to_dma(dev, pa); |
| 182 | dev_dbg(dev, "PA to DA. pa=0x%pa, da=0x%pad", &pa, &da); |
| 183 | if (da == DMA_MAPPING_ERROR) { |
| 184 | dev_err(dev, "No mapping found for PA. pa=%pa, size=%zu", &pa, |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 185 | size); |
| 186 | |
| 187 | return -ENOMEM; |
| 188 | } |
| 189 | |
Mikael Olsson | 9f176ba | 2023-11-10 15:15:34 +0100 | [diff] [blame] | 190 | mem = rproc_mem_entry_init(dev, NULL, pa, size, da, ethosu_mem_alloc, |
| 191 | ethosu_mem_release, name); |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 192 | if (!mem) |
| 193 | return -ENOMEM; |
| 194 | |
Mikael Olsson | 4bfd987 | 2024-04-16 16:36:47 +0200 | [diff] [blame] | 195 | mem->is_iomem = is_iomem; |
| 196 | |
Ledion Daja | edd2550 | 2023-10-17 09:15:32 +0200 | [diff] [blame] | 197 | dev_dbg(dev, "Add carveout mapping. dma=%pad, da=%x, va=%p, len=%zu", |
| 198 | &mem->dma, mem->da, mem->va, mem->len); |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 199 | |
| 200 | rproc_add_carveout(rproc, mem); |
| 201 | |
| 202 | return 0; |
| 203 | } |
| 204 | |
| 205 | static int ethosu_rproc_prepare(struct rproc *rproc) |
| 206 | { |
| 207 | struct device *dev = rproc->dev.parent; |
| 208 | struct device_node *np = dev->of_node; |
| 209 | struct of_phandle_iterator it; |
| 210 | struct resource res; |
| 211 | int i; |
| 212 | int ret; |
| 213 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 214 | /* Add carveout for each 'reg' device tree entry */ |
| 215 | for (i = 0; of_address_to_resource(np, i, &res) == 0; i++) { |
Ledion Daja | edd2550 | 2023-10-17 09:15:32 +0200 | [diff] [blame] | 216 | dev_dbg(dev, "Found resource. start=%llx, size=%llx", |
| 217 | res.start, resource_size(&res)); |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 218 | |
| 219 | ret = ethosu_add_carveout(rproc, res.start, |
Mikael Olsson | 4bfd987 | 2024-04-16 16:36:47 +0200 | [diff] [blame] | 220 | resource_size(&res), res.name, |
| 221 | !strncmp(res.name, "rom", 3)); |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 222 | if (ret) |
| 223 | return ret; |
| 224 | } |
| 225 | |
| 226 | of_phandle_iterator_init(&it, np, "memory-region", NULL, 0); |
| 227 | while (of_phandle_iterator_next(&it) == 0) { |
| 228 | struct reserved_mem *res_mem = of_reserved_mem_lookup(it.node); |
| 229 | |
| 230 | if (!res_mem) { |
| 231 | dev_err(dev, "Failed to look up memory region. node=%p", |
| 232 | it.node); |
| 233 | |
| 234 | return -EINVAL; |
| 235 | } |
| 236 | |
Ledion Daja | edd2550 | 2023-10-17 09:15:32 +0200 | [diff] [blame] | 237 | dev_dbg(dev, |
| 238 | "Found memory region. pa=%llx, size=%llu, name=%s", |
| 239 | res_mem->base, res_mem->size, it.node->name); |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 240 | |
| 241 | ret = ethosu_add_carveout(rproc, res_mem->base, res_mem->size, |
Mikael Olsson | 4bfd987 | 2024-04-16 16:36:47 +0200 | [diff] [blame] | 242 | it.node->name, false); |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 243 | if (ret) |
| 244 | return ret; |
| 245 | } |
| 246 | |
| 247 | return 0; |
| 248 | } |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 249 | |
| 250 | static int ethosu_rproc_start(struct rproc *rproc) |
| 251 | { |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 252 | struct ethosu_rproc *erproc = (struct ethosu_rproc *)rproc->priv; |
| 253 | struct device *dev = erproc->dev; |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 254 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 255 | dev_info(dev, "Starting up Ethos-U subsystem CPU"); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 256 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 257 | return reset_control_deassert(erproc->rstc); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 258 | } |
| 259 | |
| 260 | static int ethosu_rproc_stop(struct rproc *rproc) |
| 261 | { |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 262 | struct ethosu_rproc *erproc = (struct ethosu_rproc *)rproc->priv; |
| 263 | struct device *dev = erproc->dev; |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 264 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 265 | dev_info(dev, "Stopping Ethos-U subsystem CPU"); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 266 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 267 | return reset_control_assert(erproc->rstc); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 268 | } |
| 269 | |
| 270 | static void ethosu_rproc_kick(struct rproc *rproc, |
| 271 | int vqid) |
| 272 | { |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 273 | struct ethosu_rproc *erproc = (struct ethosu_rproc *)rproc->priv; |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 274 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 275 | dev_dbg(&rproc->dev, "Kicking Ethos-U remoteproc vqid: %d!", vqid); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 276 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 277 | mbox_send_message(erproc->ch_tx, (void *)&vqid); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 278 | } |
| 279 | |
Mikael Olsson | 9d0ea8b | 2023-06-05 16:16:36 +0200 | [diff] [blame] | 280 | static int ethosu_rproc_handle_rsc(struct rproc *rproc, |
| 281 | u32 rsc_type, |
| 282 | void *rsc, |
| 283 | int offset, |
| 284 | int avail) |
| 285 | { |
| 286 | struct ethosu_rproc *erproc = (struct ethosu_rproc *)rproc->priv; |
| 287 | struct device *dev = erproc->dev; |
| 288 | struct fw_rsc_mapping *mapping = rsc; |
| 289 | const struct bus_dma_region *map; |
| 290 | size_t num_ranges = 0U; |
| 291 | size_t i; |
| 292 | |
| 293 | if (rsc_type != RSC_MAPPING) |
| 294 | return RSC_IGNORED; |
| 295 | |
| 296 | if (struct_size(mapping, range, mapping->num_ranges) > avail) { |
| 297 | dev_err(dev, "mapping rsc is truncated\n"); |
| 298 | |
| 299 | return -EINVAL; |
| 300 | } |
| 301 | |
| 302 | for (map = dev->dma_range_map; map->size; ++map) |
| 303 | num_ranges++; |
| 304 | |
| 305 | if (num_ranges > mapping->num_ranges) { |
| 306 | dev_err(dev, |
| 307 | "Mapping rsc doesn't have enough room for DMA ranges\n"); |
| 308 | |
| 309 | return -EINVAL; |
| 310 | } |
| 311 | |
| 312 | for (i = 0U; i < num_ranges; ++i) { |
Mikael Olsson | 9d0ea8b | 2023-06-05 16:16:36 +0200 | [diff] [blame] | 313 | struct fw_rsc_map_range *range = &mapping->range[i]; |
Mikael Olsson | f1b23f3 | 2023-10-06 13:39:16 +0200 | [diff] [blame] | 314 | map = &dev->dma_range_map[i]; |
Mikael Olsson | 9d0ea8b | 2023-06-05 16:16:36 +0200 | [diff] [blame] | 315 | |
| 316 | range->da = map->dma_start; |
| 317 | range->pa = map->cpu_start; |
| 318 | range->len = map->size; |
| 319 | } |
| 320 | |
| 321 | dev_dbg(dev, "handle_rsc: Mapping rsc setup"); |
| 322 | |
| 323 | return RSC_HANDLED; |
| 324 | } |
| 325 | |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 326 | static const struct rproc_ops ethosu_rproc_ops = { |
Mikael Olsson | 9d0ea8b | 2023-06-05 16:16:36 +0200 | [diff] [blame] | 327 | .prepare = ðosu_rproc_prepare, |
| 328 | .start = ðosu_rproc_start, |
| 329 | .stop = ðosu_rproc_stop, |
| 330 | .kick = ðosu_rproc_kick, |
| 331 | .handle_rsc = ðosu_rproc_handle_rsc, |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 332 | }; |
| 333 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 334 | static int ethosu_mailbox_init(struct ethosu_rproc *erproc) |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 335 | { |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 336 | struct device *dev = erproc->dev; |
| 337 | struct mbox_client *cl = &erproc->mbox_client; |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 338 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 339 | INIT_WORK(&erproc->work, ethosu_mbox_bottom); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 340 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 341 | erproc->wq = create_singlethread_workqueue("ethosu_rproc_wq"); |
| 342 | if (!erproc->wq) { |
| 343 | dev_err(dev, "Failed to create work queue"); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 344 | |
| 345 | return -EINVAL; |
| 346 | } |
| 347 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 348 | cl->dev = dev; |
| 349 | cl->rx_callback = ethosu_mbox_top; |
| 350 | cl->tx_prepare = NULL; |
| 351 | cl->tx_done = NULL; |
| 352 | cl->tx_block = true; |
| 353 | cl->knows_txdone = false; |
| 354 | cl->tx_tout = 500; |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 355 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 356 | erproc->ch_rx = mbox_request_channel_byname(cl, "rx"); |
| 357 | if (IS_ERR(erproc->ch_rx)) { |
| 358 | dev_err(dev, "Failed to request mbox chan rx"); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 359 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 360 | return PTR_ERR(erproc->ch_rx); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 361 | } |
| 362 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 363 | erproc->ch_tx = mbox_request_channel_byname(cl, "tx"); |
| 364 | if (IS_ERR(erproc->ch_tx)) { |
Ledion Daja | edd2550 | 2023-10-17 09:15:32 +0200 | [diff] [blame] | 365 | dev_dbg(dev, "Using same channel for RX and TX"); |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 366 | erproc->ch_tx = erproc->ch_rx; |
| 367 | } |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 368 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 369 | return 0; |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 370 | } |
| 371 | |
| 372 | static const struct of_device_id ethosu_rproc_match[] = { |
Per Åstrand | 9f36f2e | 2021-09-30 09:57:34 +0200 | [diff] [blame] | 373 | { .compatible = "arm,ethosu-rproc" }, |
Per Åstrand | b9248a4 | 2022-05-18 16:05:16 +0200 | [diff] [blame] | 374 | { /* sentinel */ }, |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 375 | }; |
| 376 | |
| 377 | static int ethosu_rproc_probe(struct platform_device *pdev) |
| 378 | { |
| 379 | struct device *dev = &pdev->dev; |
| 380 | struct device_node *np = dev->of_node; |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 381 | struct ethosu_rproc *erproc; |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 382 | struct rproc *rproc; |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 383 | int ret; |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 384 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 385 | /* map the first 'memory-region' for DMA-mapping */ |
| 386 | ret = of_reserved_mem_device_init(dev); |
| 387 | if (ret) |
| 388 | return ret; |
| 389 | |
| 390 | dma_set_mask_and_coherent(dev, DMA_BIT_MASK(DMA_ADDR_BITS)); |
| 391 | |
| 392 | rproc = devm_rproc_alloc(dev, np->name, ðosu_rproc_ops, |
| 393 | fw_filename_param, |
| 394 | sizeof(*erproc)); |
| 395 | if (!rproc) |
| 396 | return -ENOMEM; |
| 397 | |
| 398 | platform_set_drvdata(pdev, rproc); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 399 | |
| 400 | /* Configure rproc */ |
| 401 | rproc->has_iommu = false; |
| 402 | rproc->auto_boot = auto_boot; |
| 403 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 404 | /* Configure Ethos-U rproc */ |
| 405 | erproc = rproc->priv; |
| 406 | erproc->dev = dev; |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 407 | |
| 408 | /* Get the reset handler for the subsystem */ |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 409 | erproc->rstc = devm_reset_control_get_exclusive_by_index(dev, 0); |
| 410 | if (IS_ERR(erproc->rstc)) { |
| 411 | dev_err(&pdev->dev, "Failed to get reset controller."); |
| 412 | |
| 413 | return PTR_ERR(erproc->rstc); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 414 | } |
| 415 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 416 | /* Allocate and initialize mailbox client */ |
| 417 | ret = ethosu_mailbox_init(erproc); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 418 | if (ret) |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 419 | return ret; |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 420 | |
| 421 | ret = rproc_add(rproc); |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 422 | if (ret) { |
| 423 | dev_err(dev, "Failed to add rproc"); |
| 424 | goto free_mbox; |
| 425 | } |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 426 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 427 | return 0; |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 428 | |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 429 | free_mbox: |
| 430 | if (erproc->wq) |
| 431 | destroy_workqueue(erproc->wq); |
| 432 | |
| 433 | mbox_free_channel(erproc->ch_rx); |
| 434 | |
| 435 | if (erproc->ch_tx != erproc->ch_rx) |
| 436 | mbox_free_channel(erproc->ch_tx); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 437 | |
| 438 | return ret; |
| 439 | } |
| 440 | |
| 441 | static int ethosu_rproc_remove(struct platform_device *pdev) |
| 442 | { |
| 443 | struct rproc *rproc = platform_get_drvdata(pdev); |
Kristofer Jonsson | a70bfde | 2023-01-12 10:00:03 +0100 | [diff] [blame] | 444 | struct ethosu_rproc *erproc = rproc->priv; |
| 445 | |
| 446 | if (erproc->wq) |
| 447 | destroy_workqueue(erproc->wq); |
| 448 | |
| 449 | if (erproc->ch_tx != erproc->ch_rx) |
| 450 | mbox_free_channel(erproc->ch_tx); |
| 451 | |
| 452 | mbox_free_channel(erproc->ch_rx); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 453 | |
| 454 | rproc_del(rproc); |
Per Åstrand | 2cd5397 | 2021-04-12 13:46:04 +0200 | [diff] [blame] | 455 | |
| 456 | return 0; |
| 457 | } |
| 458 | |
| 459 | static struct platform_driver ethosu_rproc_driver = { |
| 460 | .probe = ethosu_rproc_probe, |
| 461 | .remove = ethosu_rproc_remove, |
| 462 | .driver = { |
| 463 | .name = "ethosu-rproc", |
| 464 | .of_match_table = of_match_ptr(ethosu_rproc_match), |
| 465 | }, |
| 466 | }; |
| 467 | |
| 468 | module_platform_driver(ethosu_rproc_driver); |
| 469 | |
| 470 | MODULE_LICENSE("GPL v2"); |
| 471 | MODULE_AUTHOR("Arm Ltd"); |
| 472 | MODULE_DESCRIPTION("Arm Ethos-U NPU RemoteProc Driver"); |
| 473 | MODULE_VERSION(ETHOSU_RPROC_DRIVER_VERSION); |