1 /*
2 * Copyright (c) 2014, Mentor Graphics Corporation
3 * All rights reserved.
4 * Copyright (c) 2015 Xilinx, Inc. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * 3. Neither the name of Mentor Graphics Corporation nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
31 #include <string.h>
32 #include "openamp/remoteproc.h"
33 #include "openamp/remoteproc_loader.h"
34 #include "openamp/rsc_table_parser.h"
35 #include "openamp/env.h"
36 #include "openamp/hil.h"
37 #include "metal/sys.h"
39 /**
40 * remoteproc_resource_init
41 *
42 * Initializes resources for remoteproc remote configuration. Only
43 * remoteproc remote applications are allowed to call this function.
44 *
45 * @param rsc_info - pointer to resource table info control
46 * block
47 * @param pdata - platform data for remote processor
48 * @param channel_created - callback function for channel creation
49 * @param channel_destroyed - callback function for channel deletion
50 * @param default_cb - default callback for channel I/O
51 * @param rproc_handle - pointer to new remoteproc instance
52 *
53 * @param returns - status of function execution
54 *
55 */
56 int remoteproc_resource_init(struct rsc_table_info *rsc_info,
57 void *pdata,
58 rpmsg_chnl_cb_t channel_created,
59 rpmsg_chnl_cb_t channel_destroyed,
60 rpmsg_rx_cb_t default_cb,
61 struct remote_proc **rproc_handle)
62 {
64 struct remote_proc *rproc;
65 int status;
67 if (!rsc_info) {
68 return RPROC_ERR_PARAM;
69 }
71 rproc = env_allocate_memory(sizeof(struct remote_proc));
72 if (rproc) {
73 memset(rproc, 0x00, sizeof(struct remote_proc));
74 /* There can be only one master for remote configuration so use the
75 * rsvd cpu id for creating hil proc */
76 rproc->proc = hil_create_proc(pdata, HIL_RSVD_CPU_ID);
77 if (rproc->proc) {
78 /* Parse resource table */
79 status =
80 handle_rsc_table(rproc, rsc_info->rsc_tab,
81 rsc_info->size);
82 if (status == RPROC_SUCCESS) {
83 /* Initialize RPMSG "messaging" component */
84 *rproc_handle = rproc;
85 status =
86 rpmsg_init(NULL, rproc->proc->cpu_id,
87 &rproc->rdev, channel_created,
88 channel_destroyed, default_cb,
89 RPMSG_MASTER);
90 } else {
91 status = RPROC_ERR_NO_RSC_TABLE;
92 }
93 } else {
94 status = RPROC_ERR_CPU_ID;
95 }
96 } else {
97 status = RPROC_ERR_NO_MEM;
98 }
100 /* Cleanup in case of error */
101 if (status != RPROC_SUCCESS) {
102 *rproc_handle = 0;
103 (void)remoteproc_resource_deinit(rproc);
104 return status;
105 }
106 return status;
107 }
109 /**
110 * remoteproc_resource_deinit
111 *
112 * Uninitializes resources for remoteproc "remote" configuration.
113 *
114 * @param rproc - pointer to rproc instance
115 *
116 * @param returns - status of function execution
117 *
118 */
120 int remoteproc_resource_deinit(struct remote_proc *rproc)
121 {
122 int i = 0;
123 struct proc_vring *vring_hw = 0;
124 if (rproc) {
125 if (rproc->rdev) {
126 /* disable IPC interrupts */
127 if (rproc->proc->ops->reg_ipi_after_deinit) {
128 for (i = 0; i < 2; i++) {
129 vring_hw =
130 &rproc->proc->vdev.vring_info[i];
131 rproc->proc->ops->
132 reg_ipi_after_deinit(vring_hw);
133 }
134 }
135 rpmsg_deinit(rproc->rdev);
136 }
137 if (rproc->proc) {
138 hil_delete_proc(rproc->proc);
139 }
141 env_free_memory(rproc);
142 }
144 metal_finish();
146 /*
147 * Flush and Invalidate the caches - When the application is built with
148 * Xilinx Standalone BSP, caches are invalidated as part of boot process.
149 * Even if the master boots firmware multiple times without hard reset on
150 * same core, caches are flushed and invalidated at the end of
151 * remoteproc_resource_deinit for this run and caches would be again
152 * invalidated before starting the main thread of the application on next
153 * run to avoid any cache inconsistencies.
154 */
155 env_flush_invalidate_all_caches();
158 return RPROC_SUCCESS;
159 }
161 /**
162 * remoteproc_init
163 *
164 * Initializes resources for remoteproc master configuration. Only
165 * remoteproc master applications are allowed to call this function.
166 *
167 * @param fw_name - name of frimware
168 * @param pdata - platform data for remote processor
169 * @param channel_created - callback function for channel creation
170 * @param channel_destroyed - callback function for channel deletion
171 * @param default_cb - default callback for channel I/O
172 * @param rproc_handle - pointer to new remoteproc instance
173 *
174 * @param returns - status of function execution
175 *
176 */
177 int remoteproc_init(char *fw_name, void *pdata,
178 rpmsg_chnl_cb_t channel_created,
179 rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb,
180 struct remote_proc **rproc_handle)
181 {
183 struct remote_proc *rproc;
184 struct resource_table *rsc_table;
185 unsigned int fw_addr, fw_size, rsc_size;
186 int status;
188 if (!fw_name) {
189 return RPROC_ERR_PARAM;
190 }
192 rproc = env_allocate_memory(sizeof(struct remote_proc));
193 if (rproc) {
194 memset((void *)rproc, 0x00, sizeof(struct remote_proc));
195 /* Create proc instance */
196 rproc->proc = hil_create_proc(pdata, HIL_RSVD_CPU_ID);
197 if (rproc->proc) {
198 /* Retrieve firmware attributes */
199 status =
200 hil_get_firmware(fw_name, &fw_addr,
201 &fw_size);
202 if (!status) {
203 /* Initialize ELF loader - currently only ELF format is supported */
204 rproc->loader =
205 remoteproc_loader_init(ELF_LOADER);
206 if (rproc->loader) {
207 /* Attach the given firmware with the ELF parser/loader */
208 status =
209 remoteproc_loader_attach_firmware
210 (rproc->loader,
211 (void *)fw_addr);
212 } else {
213 status = RPROC_ERR_LOADER;
214 }
215 }
216 } else {
217 status = RPROC_ERR_NO_MEM;
218 }
219 } else {
220 status = RPROC_ERR_NO_MEM;
221 }
223 if (!status) {
224 rproc->role = RPROC_MASTER;
226 /* Get resource table from firmware */
227 rsc_table =
228 remoteproc_loader_retrieve_resource_section(rproc->loader,
229 &rsc_size);
230 if (rsc_table) {
231 /* Parse resource table */
232 status = handle_rsc_table(rproc, rsc_table, rsc_size);
233 } else {
234 status = RPROC_ERR_NO_RSC_TABLE;
235 }
236 }
238 /* Cleanup in case of error */
239 if (status != RPROC_SUCCESS) {
240 (void)remoteproc_deinit(rproc);
241 return status;
242 }
244 rproc->channel_created = channel_created;
245 rproc->channel_destroyed = channel_destroyed;
246 rproc->default_cb = default_cb;
248 *rproc_handle = rproc;
250 return status;
251 }
253 /**
254 * remoteproc_deinit
255 *
256 * Uninitializes resources for remoteproc "master" configuration.
257 *
258 * @param rproc - pointer to remote proc instance
259 *
260 * @param returns - status of function execution
261 *
262 */
263 int remoteproc_deinit(struct remote_proc *rproc)
264 {
266 if (rproc) {
267 if (rproc->loader) {
268 (void)remoteproc_loader_delete(rproc->loader);
269 rproc->loader = RPROC_NULL;
270 }
271 if (rproc->proc) {
272 hil_delete_proc(rproc->proc);
273 rproc->proc = RPROC_NULL;
274 }
275 env_free_memory(rproc);
276 }
278 metal_finish();
280 return RPROC_SUCCESS;
281 }
283 /**
284 * remoteproc_boot
285 *
286 * This function loads the image on the remote processor and starts
287 * its execution from image load address.
288 *
289 * @param rproc - pointer to remoteproc instance to boot
290 *
291 * @param returns - status of function execution
292 */
293 int remoteproc_boot(struct remote_proc *rproc)
294 {
296 void *load_addr;
297 int status;
299 if (!rproc) {
300 return RPROC_ERR_PARAM;
301 }
303 /* Stop the remote CPU */
304 hil_shutdown_cpu(rproc->proc);
306 /* Load the firmware */
307 status = remoteproc_loader_load_remote_firmware(rproc->loader);
308 if (status == RPROC_SUCCESS) {
309 load_addr = remoteproc_get_load_address(rproc->loader);
310 if (load_addr != RPROC_ERR_PTR) {
311 /* Start the remote cpu */
312 status = hil_boot_cpu(rproc->proc,
313 (unsigned int)load_addr);
314 if (status == RPROC_SUCCESS) {
315 /* Wait for remote side to come up. This delay is arbitrary and may
316 * need adjustment for different configuration of remote systems */
317 env_sleep_msec(RPROC_BOOT_DELAY);
319 /* Initialize RPMSG "messaging" component */
321 /* It is a work-around to work with remote Linux context.
322 Since the upstream Linux rpmsg implementation always
323 assumes itself to be an rpmsg master, we initialize
324 the remote device as an rpmsg master for remote Linux
325 configuration only. */
326 #if defined (OPENAMP_REMOTE_LINUX_ENABLE)
327 status =
328 rpmsg_init(NULL, rproc->proc->cpu_id,
329 &rproc->rdev,
330 rproc->channel_created,
331 rproc->channel_destroyed,
332 rproc->default_cb, RPMSG_MASTER);
333 #else
334 status =
335 rpmsg_init(NULL, rproc->proc->cpu_id,
336 &rproc->rdev,
337 rproc->channel_created,
338 rproc->channel_destroyed,
339 rproc->default_cb, RPMSG_REMOTE);
340 #endif
341 }
342 } else {
343 status = RPROC_ERR_LOADER;
344 }
345 } else {
346 status = RPROC_ERR_LOADER;
347 }
349 return status;
350 }
352 /**
353 * remoteproc_shutdown
354 *
355 * This function shutdowns the remote execution context
356 *
357 * @param rproc - pointer to remote proc instance to shutdown
358 *
359 * @param returns - status of function execution
360 */
361 int remoteproc_shutdown(struct remote_proc *rproc)
362 {
364 if (rproc) {
365 if (rproc->rdev) {
366 rpmsg_deinit(rproc->rdev);
367 rproc->rdev = RPROC_NULL;
368 }
369 if (rproc->proc) {
370 hil_shutdown_cpu(rproc->proc);
371 }
372 }
374 return RPROC_SUCCESS;
375 }