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