blob: f355634f6ac5d92972bf909d13bfd03fff592ab3 [file] [log] [blame]
Kristofer Jonsson3f5510f2023-02-08 14:23:00 +01001/*
2 * SPDX-FileCopyrightText: Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use _this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19/*****************************************************************************
20 * Includes
21 *****************************************************************************/
22
23#include "remoteproc.hpp"
24
25#include <cinttypes>
26
27#include <ethosu_log.h>
28
29/*****************************************************************************
30 * MetalIO
31 *****************************************************************************/
32
33extern "C" {
34
35__attribute__((weak)) void *ethosu_phys_to_virt(const uint64_t pa) {
36 return reinterpret_cast<void *>(pa);
37}
38}
39
40MetalIO::MetalIO() :
41 ops{.read = nullptr,
42 .write = nullptr,
43 .block_read = nullptr,
44 .block_write = nullptr,
45 .block_set = nullptr,
46 .close = nullptr,
47 .offset_to_phys = nullptr,
48 .phys_to_offset = physToOffset} {
49 remoteproc_init_mem(&mem, "shm", 0, 0, 0xffffffff, &region);
50
51 metal_io_init(&region,
52 reinterpret_cast<void *>(0), /* virt */
53 &mem.pa, /* physmap */
54 0xffffffff, /* size */
55 -1L, /* pagemask */
56 0, /* attributes */
57 &ops); /* ops */
58}
59
60remoteproc_mem *MetalIO::operator&() {
61 return &mem;
62}
63
64unsigned long MetalIO::physToOffset(metal_io_region *io, metal_phys_addr_t pa) {
65 auto offset = reinterpret_cast<unsigned long>(ethosu_phys_to_virt(pa));
66 LOG_DEBUG("Translate PA to offset. pa=%lx, offset=%lx", pa, offset);
67 return offset;
68}
69
70/*****************************************************************************
71 * RProc
72 *****************************************************************************/
73
74RProc::RProc(Mailbox::Mailbox &_mailbox, resource_table &table, size_t tableSize, MetalIO &_mem) :
75 mailbox(_mailbox), mem(_mem),
76 ops{
77 .init = init, // initialize the remoteproc instance
78 .remove = remove, // remove the remoteproc instance
79 .mmap = nullptr, // memory mapped the memory with physical address as input
80 .handle_rsc = nullptr, // handle the vendor specific resource
81 .config = nullptr, // configure the remoteproc to make it ready to load and run executable
82 .start = nullptr, // kick the remoteproc to run application
83 .stop = nullptr, // stop the remoteproc from running application, the resource such as memory may not be off.
84 .shutdown = nullptr, // shutdown the remoteproc and release its resources.
85 .notify = notify, // notify the remote
86 .get_mem = nullptr, // get remoteproc memory I/O region.
87 },
88 vdev(nullptr), notifySemaphore(xSemaphoreCreateBinary()) {
89 mailbox.registerCallback(mailboxCallback, static_cast<void *>(this));
90
91 if (!remoteproc_init(&rproc, &ops, this)) {
92 LOG_ERR("Failed to intialize remoteproc");
93 abort();
94 }
95
96 int ret = remoteproc_set_rsc_table(&rproc, &table, tableSize);
97 if (ret) {
98 LOG_ERR("Failed to set resource table. ret=%d", ret);
99 abort();
100 }
101
102 vdev = remoteproc_create_virtio(&rproc, 0, VIRTIO_DEV_DEVICE, nullptr);
103 if (!vdev) {
104 LOG_ERR("Failed to create vdev");
105 abort();
106 }
107
108 BaseType_t taskret = xTaskCreate(notifyTask, "notifyTask", 1024, this, 2, &notifyHandle);
109 if (taskret != pdPASS) {
110 LOG_ERR("Failed to create remoteproc notify task");
111 abort();
112 }
113}
114
115RProc::~RProc() {
116 mailbox.deregisterCallback(mailboxCallback, static_cast<void *>(this));
117 vTaskDelete(notifyHandle);
118}
119
120remoteproc *RProc::getRProc() {
121 return &rproc;
122}
123
124virtio_device *RProc::getVDev() {
125 return vdev;
126}
127
128void RProc::mailboxCallback(void *userArg) {
129 auto _this = static_cast<RProc *>(userArg);
130
131 xSemaphoreGiveFromISR(_this->notifySemaphore, nullptr);
132}
133
134void RProc::notifyTask(void *param) {
135 LOG_DEBUG("Starting message notify task");
136
137 auto _this = static_cast<RProc *>(param);
138
139 while (true) {
140 // Wait for event
141 xSemaphoreTake(_this->notifySemaphore, portMAX_DELAY);
142
143 // Read virtio queue and notify all rpmsg clients
144 rproc_virtio_notified(_this->vdev, RSC_NOTIFY_ID_ANY);
145 }
146}
147
148struct remoteproc *RProc::init(remoteproc *rproc, const remoteproc_ops *ops, void *arg) {
149 LOG_DEBUG("");
150
151 auto _this = static_cast<RProc *>(arg);
152
153 rproc->ops = ops;
154 rproc->priv = arg;
155 remoteproc_add_mem(rproc, &_this->mem);
156
157 return rproc;
158}
159
160void RProc::remove(remoteproc *rproc) {
161 LOG_DEBUG("");
162}
163
164int RProc::notify(remoteproc *rproc, uint32_t id) {
165 LOG_DEBUG("");
166
167 auto *_this = static_cast<RProc *>(rproc->priv);
168 _this->mailbox.sendMessage();
169 return 0;
170}
171
172/*****************************************************************************
173 * Rpmsg
174 *****************************************************************************/
175
176Rpmsg::Rpmsg(RProc &rproc, const char *const name) {
177
178 metal_io_region *region = remoteproc_get_io_with_name(rproc.getRProc(), "shm");
179 if (!region) {
180 LOG_ERR("Failed to get shared mem region");
181 abort();
182 }
183
184 if (rpmsg_init_vdev(&rvdev, rproc.getVDev(), nullptr, region, nullptr)) {
185 LOG_ERR("Failed to initialize rpmsg vdev");
186 abort();
187 }
188
189 rdev = rpmsg_virtio_get_rpmsg_device(&rvdev);
190 if (!rdev) {
191 LOG_ERR("Failed to get rpmsg dev");
192 abort();
193 }
194
195 int ret =
196 rpmsg_create_ept(&endpoint, rdev, name, RPMSG_ADDR_ANY, RPMSG_ADDR_ANY, endpointCallback, nsUnbindCallback);
197 if (ret != RPMSG_SUCCESS) {
198 LOG_ERR("Failed to create rpmsg endpoint. ret=%d", ret);
199 abort();
200 }
201
202 endpoint.priv = static_cast<void *>(this);
203}
204
205int Rpmsg::send(void *data, size_t len, uint32_t dst) {
206 LOG_DEBUG("Sending rpmsg. dst=%" PRIu32 ", len=%zu", dst, len);
207
208 int ret = rpmsg_sendto(&endpoint, data, len, dst);
209 return ret;
210}
211
212void *Rpmsg::physicalToVirtual(metal_phys_addr_t pa) {
213 return metal_io_phys_to_virt(rvdev.shbuf_io, pa);
214}
215
216void Rpmsg::rpmsgNsBind(rpmsg_device *rdev, const char *name, uint32_t dest) {
217 LOG_DEBUG("");
218}
219
220void Rpmsg::nsUnbindCallback(rpmsg_endpoint *ept) {
221 LOG_DEBUG("");
222}
223
224int Rpmsg::endpointCallback(rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv) {
225 LOG_DEBUG("src=%" PRIX32 ", len=%zu", src, len);
226
227 auto _this = static_cast<Rpmsg *>(priv);
228 _this->handleMessage(data, len, src);
229
230 return 0;
231}
232
233int Rpmsg::handleMessage(void *data, size_t len, uint32_t src) {
234 LOG_DEBUG("Receiving rpmsg. src=%" PRIu32 ", len=%zu", src, len);
235
236 auto c = static_cast<char *>(data);
237 for (size_t i = 0; i < len; i++) {
238 printf("%c", c[i]);
239 }
240 printf("\n");
241
242 return 0;
243}