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