32750e1581efece442facd082a7ae6d6c7fc91f9
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 channel_created - callback function for channel creation
48 * @param channel_destroyed - callback function for channel deletion
49 * @param default_cb - default callback for channel I/O
50 * @param rproc_handle - pointer to new remoteproc instance
51 *
52 * @param returns - status of function execution
53 *
54 */
55 int remoteproc_resource_init(struct rsc_table_info *rsc_info,
56 rpmsg_chnl_cb_t channel_created,
57 rpmsg_chnl_cb_t channel_destroyed,
58 rpmsg_rx_cb_t default_cb,
59 struct remote_proc **rproc_handle)
60 {
62 struct remote_proc *rproc;
63 int status;
65 if (!rsc_info) {
66 return RPROC_ERR_PARAM;
67 }
69 rproc = env_allocate_memory(sizeof(struct remote_proc));
70 if (rproc) {
71 memset(rproc, 0x00, sizeof(struct remote_proc));
72 /* There can be only one master for remote configuration so use the
73 * rsvd cpu id for creating hil proc */
74 rproc->proc = hil_create_proc(HIL_RSVD_CPU_ID);
75 if (rproc->proc) {
76 /* Parse resource table */
77 status =
78 handle_rsc_table(rproc, rsc_info->rsc_tab,
79 rsc_info->size);
80 if (status == RPROC_SUCCESS) {
81 /* Initialize RPMSG "messaging" component */
82 *rproc_handle = rproc;
83 status =
84 rpmsg_init(rproc->proc->cpu_id,
85 &rproc->rdev, channel_created,
86 channel_destroyed, default_cb,
87 RPMSG_MASTER);
88 } else {
89 status = RPROC_ERR_NO_RSC_TABLE;
90 }
91 } else {
92 status = RPROC_ERR_CPU_ID;
93 }
94 } else {
95 status = RPROC_ERR_NO_MEM;
96 }
98 /* Cleanup in case of error */
99 if (status != RPROC_SUCCESS) {
100 *rproc_handle = 0;
101 (void)remoteproc_resource_deinit(rproc);
102 return status;
103 }
104 return status;
105 }
107 /**
108 * remoteproc_resource_deinit
109 *
110 * Uninitializes resources for remoteproc "remote" configuration.
111 *
112 * @param rproc - pointer to rproc instance
113 *
114 * @param returns - status of function execution
115 *
116 */
118 int remoteproc_resource_deinit(struct remote_proc *rproc)
119 {
120 int i = 0;
121 struct proc_vring *vring_hw = 0;
122 if (rproc) {
123 if (rproc->rdev) {
124 /* disable IPC interrupts */
125 if (rproc->proc->ops->reg_ipi_after_deinit) {
126 for (i = 0; i < 2; i++) {
127 vring_hw =
128 &rproc->proc->vdev.vring_info[i];
129 rproc->proc->ops->
130 reg_ipi_after_deinit(vring_hw);
131 }
132 }
133 rpmsg_deinit(rproc->rdev);
134 }
135 if (rproc->proc) {
136 hil_delete_proc(rproc->proc);
137 }
139 env_free_memory(rproc);
140 }
142 metal_finish();
144 /*
145 * Flush and Invalidate the caches - When the application is built with
146 * Xilinx Standalone BSP, caches are invalidated as part of boot process.
147 * Even if the master boots firmware multiple times without hard reset on
148 * same core, caches are flushed and invalidated at the end of
149 * remoteproc_resource_deinit for this run and caches would be again
150 * invalidated before starting the main thread of the application on next
151 * run to avoid any cache inconsistencies.
152 */
153 env_flush_invalidate_all_caches();
156 return RPROC_SUCCESS;
157 }
159 /**
160 * remoteproc_init
161 *
162 * Initializes resources for remoteproc master configuration. Only
163 * remoteproc master applications are allowed to call this function.
164 *
165 * @param fw_name - name of frimware
166 * @param channel_created - callback function for channel creation
167 * @param channel_destroyed - callback function for channel deletion
168 * @param default_cb - default callback for channel I/O
169 * @param rproc_handle - pointer to new remoteproc instance
170 *
171 * @param returns - status of function execution
172 *
173 */
174 int remoteproc_init(char *fw_name, rpmsg_chnl_cb_t channel_created,
175 rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb,
176 struct remote_proc **rproc_handle)
177 {
179 struct remote_proc *rproc;
180 struct resource_table *rsc_table;
181 unsigned int fw_addr, fw_size, rsc_size;
182 int status, cpu_id;
184 if (!fw_name) {
185 return RPROC_ERR_PARAM;
186 }
188 rproc = env_allocate_memory(sizeof(struct remote_proc));
189 if (rproc) {
190 memset((void *)rproc, 0x00, sizeof(struct remote_proc));
191 /* Get CPU ID for the given firmware name */
192 cpu_id = hil_get_cpuforfw(fw_name);
193 if (cpu_id >= 0) {
194 /* Create proc instance */
195 rproc->proc = hil_create_proc(cpu_id);
196 if (rproc->proc) {
197 /* Retrieve firmware attributes */
198 status =
199 hil_get_firmware(fw_name, &fw_addr,
200 &fw_size);
201 if (!status) {
202 /* Initialize ELF loader - currently only ELF format is supported */
203 rproc->loader =
204 remoteproc_loader_init(ELF_LOADER);
205 if (rproc->loader) {
206 /* Attach the given firmware with the ELF parser/loader */
207 status =
208 remoteproc_loader_attach_firmware
209 (rproc->loader,
210 (void *)fw_addr);
211 } else {
212 status = RPROC_ERR_LOADER;
213 }
214 }
215 } else {
216 status = RPROC_ERR_NO_MEM;
217 }
218 } else {
219 status = RPROC_ERR_INVLD_FW;
220 }
221 } else {
222 status = RPROC_ERR_NO_MEM;
223 }
225 if (!status) {
226 rproc->role = RPROC_MASTER;
228 /* Get resource table from firmware */
229 rsc_table =
230 remoteproc_loader_retrieve_resource_section(rproc->loader,
231 &rsc_size);
232 if (rsc_table) {
233 /* Parse resource table */
234 status = handle_rsc_table(rproc, rsc_table, rsc_size);
235 } else {
236 status = RPROC_ERR_NO_RSC_TABLE;
237 }
238 }
240 /* Cleanup in case of error */
241 if (status != RPROC_SUCCESS) {
242 (void)remoteproc_deinit(rproc);
243 return status;
244 }
246 rproc->channel_created = channel_created;
247 rproc->channel_destroyed = channel_destroyed;
248 rproc->default_cb = default_cb;
250 *rproc_handle = rproc;
252 return status;
253 }
255 /**
256 * remoteproc_deinit
257 *
258 * Uninitializes resources for remoteproc "master" configuration.
259 *
260 * @param rproc - pointer to remote proc instance
261 *
262 * @param returns - status of function execution
263 *
264 */
265 int remoteproc_deinit(struct remote_proc *rproc)
266 {
268 if (rproc) {
269 if (rproc->loader) {
270 (void)remoteproc_loader_delete(rproc->loader);
271 rproc->loader = RPROC_NULL;
272 }
273 if (rproc->proc) {
274 hil_delete_proc(rproc->proc);
275 rproc->proc = RPROC_NULL;
276 }
277 env_free_memory(rproc);
278 }
280 metal_finish();
282 return RPROC_SUCCESS;
283 }
285 /**
286 * remoteproc_boot
287 *
288 * This function loads the image on the remote processor and starts
289 * its execution from image load address.
290 *
291 * @param rproc - pointer to remoteproc instance to boot
292 *
293 * @param returns - status of function execution
294 */
295 int remoteproc_boot(struct remote_proc *rproc)
296 {
298 void *load_addr;
299 int status;
301 if (!rproc) {
302 return RPROC_ERR_PARAM;
303 }
305 /* Stop the remote CPU */
306 hil_shutdown_cpu(rproc->proc);
308 /* Load the firmware */
309 status = remoteproc_loader_load_remote_firmware(rproc->loader);
310 if (status == RPROC_SUCCESS) {
311 load_addr = remoteproc_get_load_address(rproc->loader);
312 if (load_addr != RPROC_ERR_PTR) {
313 /* Start the remote cpu */
314 status = hil_boot_cpu(rproc->proc,
315 (unsigned int)load_addr);
316 if (status == RPROC_SUCCESS) {
317 /* Wait for remote side to come up. This delay is arbitrary and may
318 * need adjustment for different configuration of remote systems */
319 env_sleep_msec(RPROC_BOOT_DELAY);
321 /* Initialize RPMSG "messaging" component */
323 /* It is a work-around to work with remote Linux context.
324 Since the upstream Linux rpmsg implementation always
325 assumes itself to be an rpmsg master, we initialize
326 the remote device as an rpmsg master for remote Linux
327 configuration only. */
328 #if defined (OPENAMP_REMOTE_LINUX_ENABLE)
329 status =
330 rpmsg_init(rproc->proc->cpu_id,
331 &rproc->rdev,
332 rproc->channel_created,
333 rproc->channel_destroyed,
334 rproc->default_cb, RPMSG_MASTER);
335 #else
336 status =
337 rpmsg_init(rproc->proc->cpu_id,
338 &rproc->rdev,
339 rproc->channel_created,
340 rproc->channel_destroyed,
341 rproc->default_cb, RPMSG_REMOTE);
342 #endif
343 }
344 } else {
345 status = RPROC_ERR_LOADER;
346 }
347 } else {
348 status = RPROC_ERR_LOADER;
349 }
351 return status;
352 }
354 /**
355 * remoteproc_shutdown
356 *
357 * This function shutdowns the remote execution context
358 *
359 * @param rproc - pointer to remote proc instance to shutdown
360 *
361 * @param returns - status of function execution
362 */
363 int remoteproc_shutdown(struct remote_proc *rproc)
364 {
366 if (rproc) {
367 if (rproc->rdev) {
368 rpmsg_deinit(rproc->rdev);
369 rproc->rdev = RPROC_NULL;
370 }
371 if (rproc->proc) {
372 hil_shutdown_cpu(rproc->proc);
373 }
374 }
376 return RPROC_SUCCESS;
377 }