| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * ST's Remote Processor Control Driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2015 STMicroelectronics - All Rights Reserved |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Author: Ludovic Barre <ludovic.barre@st.com> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 9 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 10 | | - * published by the Free Software Foundation. |
|---|
| 11 | 8 | */ |
|---|
| 12 | 9 | |
|---|
| 13 | 10 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 19 | 16 | #include <linux/mfd/syscon.h> |
|---|
| 20 | 17 | #include <linux/module.h> |
|---|
| 21 | 18 | #include <linux/of.h> |
|---|
| 19 | +#include <linux/of_address.h> |
|---|
| 22 | 20 | #include <linux/of_device.h> |
|---|
| 23 | 21 | #include <linux/of_reserved_mem.h> |
|---|
| 24 | 22 | #include <linux/platform_device.h> |
|---|
| .. | .. |
|---|
| 91 | 89 | dev_err(dev, "failed to send message via mbox: %d\n", ret); |
|---|
| 92 | 90 | } |
|---|
| 93 | 91 | |
|---|
| 92 | +static int st_rproc_mem_alloc(struct rproc *rproc, |
|---|
| 93 | + struct rproc_mem_entry *mem) |
|---|
| 94 | +{ |
|---|
| 95 | + struct device *dev = rproc->dev.parent; |
|---|
| 96 | + void *va; |
|---|
| 97 | + |
|---|
| 98 | + va = ioremap_wc(mem->dma, mem->len); |
|---|
| 99 | + if (!va) { |
|---|
| 100 | + dev_err(dev, "Unable to map memory region: %pa+%zx\n", |
|---|
| 101 | + &mem->dma, mem->len); |
|---|
| 102 | + return -ENOMEM; |
|---|
| 103 | + } |
|---|
| 104 | + |
|---|
| 105 | + /* Update memory entry va */ |
|---|
| 106 | + mem->va = va; |
|---|
| 107 | + |
|---|
| 108 | + return 0; |
|---|
| 109 | +} |
|---|
| 110 | + |
|---|
| 111 | +static int st_rproc_mem_release(struct rproc *rproc, |
|---|
| 112 | + struct rproc_mem_entry *mem) |
|---|
| 113 | +{ |
|---|
| 114 | + iounmap(mem->va); |
|---|
| 115 | + |
|---|
| 116 | + return 0; |
|---|
| 117 | +} |
|---|
| 118 | + |
|---|
| 119 | +static int st_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) |
|---|
| 120 | +{ |
|---|
| 121 | + struct device *dev = rproc->dev.parent; |
|---|
| 122 | + struct device_node *np = dev->of_node; |
|---|
| 123 | + struct rproc_mem_entry *mem; |
|---|
| 124 | + struct reserved_mem *rmem; |
|---|
| 125 | + struct of_phandle_iterator it; |
|---|
| 126 | + int index = 0; |
|---|
| 127 | + |
|---|
| 128 | + of_phandle_iterator_init(&it, np, "memory-region", NULL, 0); |
|---|
| 129 | + while (of_phandle_iterator_next(&it) == 0) { |
|---|
| 130 | + rmem = of_reserved_mem_lookup(it.node); |
|---|
| 131 | + if (!rmem) { |
|---|
| 132 | + dev_err(dev, "unable to acquire memory-region\n"); |
|---|
| 133 | + return -EINVAL; |
|---|
| 134 | + } |
|---|
| 135 | + |
|---|
| 136 | + /* No need to map vdev buffer */ |
|---|
| 137 | + if (strcmp(it.node->name, "vdev0buffer")) { |
|---|
| 138 | + /* Register memory region */ |
|---|
| 139 | + mem = rproc_mem_entry_init(dev, NULL, |
|---|
| 140 | + (dma_addr_t)rmem->base, |
|---|
| 141 | + rmem->size, rmem->base, |
|---|
| 142 | + st_rproc_mem_alloc, |
|---|
| 143 | + st_rproc_mem_release, |
|---|
| 144 | + it.node->name); |
|---|
| 145 | + } else { |
|---|
| 146 | + /* Register reserved memory for vdev buffer allocation */ |
|---|
| 147 | + mem = rproc_of_resm_mem_entry_init(dev, index, |
|---|
| 148 | + rmem->size, |
|---|
| 149 | + rmem->base, |
|---|
| 150 | + it.node->name); |
|---|
| 151 | + } |
|---|
| 152 | + |
|---|
| 153 | + if (!mem) |
|---|
| 154 | + return -ENOMEM; |
|---|
| 155 | + |
|---|
| 156 | + rproc_add_carveout(rproc, mem); |
|---|
| 157 | + index++; |
|---|
| 158 | + } |
|---|
| 159 | + |
|---|
| 160 | + return rproc_elf_load_rsc_table(rproc, fw); |
|---|
| 161 | +} |
|---|
| 162 | + |
|---|
| 94 | 163 | static int st_rproc_start(struct rproc *rproc) |
|---|
| 95 | 164 | { |
|---|
| 96 | 165 | struct st_rproc *ddata = rproc->priv; |
|---|
| .. | .. |
|---|
| 121 | 190 | } |
|---|
| 122 | 191 | } |
|---|
| 123 | 192 | |
|---|
| 124 | | - dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr); |
|---|
| 193 | + dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr); |
|---|
| 125 | 194 | |
|---|
| 126 | 195 | return 0; |
|---|
| 127 | 196 | |
|---|
| .. | .. |
|---|
| 158 | 227 | } |
|---|
| 159 | 228 | |
|---|
| 160 | 229 | static const struct rproc_ops st_rproc_ops = { |
|---|
| 161 | | - .kick = st_rproc_kick, |
|---|
| 162 | | - .start = st_rproc_start, |
|---|
| 163 | | - .stop = st_rproc_stop, |
|---|
| 230 | + .kick = st_rproc_kick, |
|---|
| 231 | + .start = st_rproc_start, |
|---|
| 232 | + .stop = st_rproc_stop, |
|---|
| 233 | + .parse_fw = st_rproc_parse_fw, |
|---|
| 234 | + .load = rproc_elf_load_segments, |
|---|
| 235 | + .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, |
|---|
| 236 | + .sanity_check = rproc_elf_sanity_check, |
|---|
| 237 | + .get_boot_addr = rproc_elf_get_boot_addr, |
|---|
| 164 | 238 | }; |
|---|
| 165 | 239 | |
|---|
| 166 | 240 | /* |
|---|
| .. | .. |
|---|
| 252 | 326 | if (err) { |
|---|
| 253 | 327 | dev_err(dev, "Boot offset not found\n"); |
|---|
| 254 | 328 | return -EINVAL; |
|---|
| 255 | | - } |
|---|
| 256 | | - |
|---|
| 257 | | - err = of_reserved_mem_device_init(dev); |
|---|
| 258 | | - if (err) { |
|---|
| 259 | | - dev_err(dev, "Failed to obtain shared memory\n"); |
|---|
| 260 | | - return err; |
|---|
| 261 | 329 | } |
|---|
| 262 | 330 | |
|---|
| 263 | 331 | err = clk_prepare(ddata->clk); |
|---|
| .. | .. |
|---|
| 386 | 454 | rproc_del(rproc); |
|---|
| 387 | 455 | |
|---|
| 388 | 456 | clk_disable_unprepare(ddata->clk); |
|---|
| 389 | | - |
|---|
| 390 | | - of_reserved_mem_device_release(&pdev->dev); |
|---|
| 391 | 457 | |
|---|
| 392 | 458 | for (i = 0; i < ST_RPROC_MAX_VRING * MBOX_MAX; i++) |
|---|
| 393 | 459 | mbox_free_channel(ddata->mbox_chan[i]); |
|---|