blob: 48dd4e8fee0a99335754ff2988696dda85b26a6a [file] [log] [blame]
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +01001/*
Mikael Olsson296c4c22024-01-16 10:51:11 +01002 * SPDX-FileCopyrightText: Copyright 2022-2024 Arm Limited and/or its affiliates <open-source-office@arm.com>
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +01003 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the License); you may
6 * not use _this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*****************************************************************************
19 * Includes
20 *****************************************************************************/
21
22#include "remoteproc.hpp"
23
24#include <cinttypes>
25
26#include <ethosu_log.h>
27
Mikael Olsson67add212023-05-31 19:00:48 +020028namespace {
29void setupRProcMem(remoteproc &rproc,
30 metal_phys_addr_t pa,
31 metal_phys_addr_t da,
32 size_t size,
33 remoteproc_mem &mem,
34 metal_io_region &region) {
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +010035
Mikael Olsson67add212023-05-31 19:00:48 +020036 remoteproc_init_mem(&mem, nullptr, pa, da, size, &region);
37 metal_io_init(&region, (void *)da, &mem.pa, size, -1, 0, nullptr);
38 remoteproc_add_mem(&rproc, &mem);
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +010039}
Mikael Olsson67add212023-05-31 19:00:48 +020040}; // namespace
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +010041
42/*****************************************************************************
43 * RProc
44 *****************************************************************************/
45
Mikael Olsson67add212023-05-31 19:00:48 +020046RProc::RProc(Mailbox::Mailbox &_mailbox, resource_table &table, size_t tableSize) :
Mikael Olssonc2185832024-04-05 16:58:49 +020047 mailbox(_mailbox), ops({}), vdev(nullptr), rsc_mem(), rsc_region(), mems(), regions(),
48 notifySemaphore(xSemaphoreCreateBinary()), notifyHandle() {
Mikael Olsson296c4c22024-01-16 10:51:11 +010049 ops.init = init; // initialize the remoteproc instance
50 ops.remove = remove; // remove the remoteproc instance
51 ops.handle_rsc = handle_rsc; // handle the vendor specific resource
52 ops.notify = notify; // notify the remote
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +010053 mailbox.registerCallback(mailboxCallback, static_cast<void *>(this));
54
55 if (!remoteproc_init(&rproc, &ops, this)) {
56 LOG_ERR("Failed to intialize remoteproc");
57 abort();
58 }
59
Mikael Olsson67add212023-05-31 19:00:48 +020060 // Setup memory region for resource table
61 const metal_phys_addr_t rsc_addr = reinterpret_cast<metal_phys_addr_t>(&table);
62 // No translation is needed for rsc_addr because it already contains the DA
63 // so PA is set to DA
64 setupRProcMem(rproc, rsc_addr, rsc_addr, tableSize, rsc_mem, rsc_region);
65
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +010066 int ret = remoteproc_set_rsc_table(&rproc, &table, tableSize);
67 if (ret) {
68 LOG_ERR("Failed to set resource table. ret=%d", ret);
69 abort();
70 }
71
72 vdev = remoteproc_create_virtio(&rproc, 0, VIRTIO_DEV_DEVICE, nullptr);
73 if (!vdev) {
74 LOG_ERR("Failed to create vdev");
75 abort();
76 }
77
78 BaseType_t taskret = xTaskCreate(notifyTask, "notifyTask", 1024, this, 2, &notifyHandle);
79 if (taskret != pdPASS) {
80 LOG_ERR("Failed to create remoteproc notify task");
81 abort();
82 }
83}
84
85RProc::~RProc() {
86 mailbox.deregisterCallback(mailboxCallback, static_cast<void *>(this));
87 vTaskDelete(notifyHandle);
Mikael Olsson30902c32024-04-02 17:41:55 +020088 vSemaphoreDelete(notifySemaphore);
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +010089}
90
91remoteproc *RProc::getRProc() {
92 return &rproc;
93}
94
95virtio_device *RProc::getVDev() {
96 return vdev;
97}
98
99void RProc::mailboxCallback(void *userArg) {
100 auto _this = static_cast<RProc *>(userArg);
101
102 xSemaphoreGiveFromISR(_this->notifySemaphore, nullptr);
103}
104
105void RProc::notifyTask(void *param) {
106 LOG_DEBUG("Starting message notify task");
107
108 auto _this = static_cast<RProc *>(param);
109
110 while (true) {
111 // Wait for event
112 xSemaphoreTake(_this->notifySemaphore, portMAX_DELAY);
113
114 // Read virtio queue and notify all rpmsg clients
115 rproc_virtio_notified(_this->vdev, RSC_NOTIFY_ID_ANY);
116 }
117}
118
119struct remoteproc *RProc::init(remoteproc *rproc, const remoteproc_ops *ops, void *arg) {
120 LOG_DEBUG("");
121
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +0100122 rproc->ops = ops;
123 rproc->priv = arg;
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +0100124
125 return rproc;
126}
127
Mikael Olsson67add212023-05-31 19:00:48 +0200128int RProc::handle_rsc(remoteproc *rproc, void *rsc, size_t len) {
129 auto _this = static_cast<RProc *>(rproc->priv);
130 struct fw_rsc_mapping *mapping = static_cast<fw_rsc_mapping *>(rsc);
131
132 if (mapping->type != RSC_MAPPING) {
133 LOG_ERR("Unknown resource type %" PRIu32, mapping->type);
134 return -RPROC_ERR_RSC_TAB_NS;
135 }
136
137 for (uint32_t i = 0; i < mapping->num_ranges; ++i) {
138 const fw_rsc_map_range *range = &mapping->range[i];
139 if (range->len == 0) {
140 LOG_DEBUG("Ignored zero length memory map range[%" PRIu32 "]", i);
141 continue;
142 }
143 setupRProcMem(*rproc, range->pa, range->da, range->len, _this->mems[i], _this->regions[i]);
144 }
145
146 return 0;
147}
148
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +0100149void RProc::remove(remoteproc *rproc) {
150 LOG_DEBUG("");
151}
152
153int RProc::notify(remoteproc *rproc, uint32_t id) {
154 LOG_DEBUG("");
155
156 auto *_this = static_cast<RProc *>(rproc->priv);
157 _this->mailbox.sendMessage();
158 return 0;
159}
160
161/*****************************************************************************
162 * Rpmsg
163 *****************************************************************************/
164
Mikael Olssonf870d112024-04-02 17:20:47 +0200165Rpmsg::Rpmsg(RProc &rproc, const char *const name) : rvdev({}), rdev(), endpoint({}) {
Mikael Olsson67add212023-05-31 19:00:48 +0200166 struct virtio_device *vdev = rproc.getVDev();
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +0100167
Mikael Olsson67add212023-05-31 19:00:48 +0200168 if (vdev->vrings_num != ResourceTable::NUM_VRINGS) {
169 LOG_ERR("Invalid number of vrings");
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +0100170 abort();
171 }
172
Mikael Olsson67add212023-05-31 19:00:48 +0200173 // Vdev can use the same IO region for translations as the vring
174 if (rpmsg_init_vdev(&rvdev, vdev, nullptr, vdev->vrings_info[0].io, nullptr)) {
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +0100175 LOG_ERR("Failed to initialize rpmsg vdev");
176 abort();
177 }
178
179 rdev = rpmsg_virtio_get_rpmsg_device(&rvdev);
180 if (!rdev) {
181 LOG_ERR("Failed to get rpmsg dev");
182 abort();
183 }
184
185 int ret =
186 rpmsg_create_ept(&endpoint, rdev, name, RPMSG_ADDR_ANY, RPMSG_ADDR_ANY, endpointCallback, nsUnbindCallback);
187 if (ret != RPMSG_SUCCESS) {
188 LOG_ERR("Failed to create rpmsg endpoint. ret=%d", ret);
189 abort();
190 }
191
192 endpoint.priv = static_cast<void *>(this);
193}
194
195int Rpmsg::send(void *data, size_t len, uint32_t dst) {
196 LOG_DEBUG("Sending rpmsg. dst=%" PRIu32 ", len=%zu", dst, len);
197
198 int ret = rpmsg_sendto(&endpoint, data, len, dst);
199 return ret;
200}
201
202void *Rpmsg::physicalToVirtual(metal_phys_addr_t pa) {
203 return metal_io_phys_to_virt(rvdev.shbuf_io, pa);
204}
205
206void Rpmsg::rpmsgNsBind(rpmsg_device *rdev, const char *name, uint32_t dest) {
207 LOG_DEBUG("");
208}
209
210void Rpmsg::nsUnbindCallback(rpmsg_endpoint *ept) {
211 LOG_DEBUG("");
212}
213
214int Rpmsg::endpointCallback(rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv) {
215 LOG_DEBUG("src=%" PRIX32 ", len=%zu", src, len);
216
217 auto _this = static_cast<Rpmsg *>(priv);
218 _this->handleMessage(data, len, src);
219
220 return 0;
221}
222
223int Rpmsg::handleMessage(void *data, size_t len, uint32_t src) {
224 LOG_DEBUG("Receiving rpmsg. src=%" PRIu32 ", len=%zu", src, len);
225
226 auto c = static_cast<char *>(data);
227 for (size_t i = 0; i < len; i++) {
228 printf("%c", c[i]);
229 }
230 printf("\n");
231
232 return 0;
233}