a7a157ad508fc1792f63aaf2a099e456d8e2136b
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 /* Disable the caches - This is required if master boots firmwares
149 * multiple times without hard reset on same core. If caches are
150 * not invalidated at this point in time then subsequent firmware
151 * boots on the same core may experience cache inconsistencies.
152 *
153 */
154 env_disable_cache();
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 /* Initialize environment component */
189 status = env_init();
190 if (status != RPROC_SUCCESS) {
191 return status;
192 }
194 rproc = env_allocate_memory(sizeof(struct remote_proc));
195 if (rproc) {
196 env_memset((void *)rproc, 0x00, sizeof(struct remote_proc));
197 /* Get CPU ID for the given firmware name */
198 cpu_id = hil_get_cpuforfw(fw_name);
199 if (cpu_id >= 0) {
200 /* Create proc instance */
201 rproc->proc = hil_create_proc(cpu_id);
202 if (rproc->proc) {
203 /* Retrieve firmware attributes */
204 status =
205 hil_get_firmware(fw_name, &fw_addr,
206 &fw_size);
207 if (!status) {
208 /* Initialize ELF loader - currently only ELF format is supported */
209 rproc->loader =
210 remoteproc_loader_init(ELF_LOADER);
211 if (rproc->loader) {
212 /* Attach the given firmware with the ELF parser/loader */
213 status =
214 remoteproc_loader_attach_firmware
215 (rproc->loader,
216 (void *)fw_addr);
217 } else {
218 status = RPROC_ERR_LOADER;
219 }
220 }
221 } else {
222 status = RPROC_ERR_NO_MEM;
223 }
224 } else {
225 status = RPROC_ERR_INVLD_FW;
226 }
227 } else {
228 status = RPROC_ERR_NO_MEM;
229 }
231 if (!status) {
232 rproc->role = RPROC_MASTER;
234 /* Get resource table from firmware */
235 rsc_table =
236 remoteproc_loader_retrieve_resource_section(rproc->loader,
237 &rsc_size);
238 if (rsc_table) {
239 /* Parse resource table */
240 status = handle_rsc_table(rproc, rsc_table, rsc_size);
241 } else {
242 status = RPROC_ERR_NO_RSC_TABLE;
243 }
244 }
246 /* Cleanup in case of error */
247 if (status != RPROC_SUCCESS) {
248 (void)remoteproc_deinit(rproc);
249 return status;
250 }
252 rproc->channel_created = channel_created;
253 rproc->channel_destroyed = channel_destroyed;
254 rproc->default_cb = default_cb;
256 *rproc_handle = rproc;
258 return status;
259 }
261 /**
262 * remoteproc_deinit
263 *
264 * Uninitializes resources for remoteproc "master" configuration.
265 *
266 * @param rproc - pointer to remote proc instance
267 *
268 * @param returns - status of function execution
269 *
270 */
271 int remoteproc_deinit(struct remote_proc *rproc)
272 {
274 if (rproc) {
275 if (rproc->loader) {
276 (void)remoteproc_loader_delete(rproc->loader);
277 rproc->loader = RPROC_NULL;
278 }
279 if (rproc->proc) {
280 hil_delete_proc(rproc->proc);
281 rproc->proc = RPROC_NULL;
282 }
283 env_free_memory(rproc);
284 }
286 env_deinit();
288 return RPROC_SUCCESS;
289 }
291 /**
292 * remoteproc_boot
293 *
294 * This function loads the image on the remote processor and starts
295 * its execution from image load address.
296 *
297 * @param rproc - pointer to remoteproc instance to boot
298 *
299 * @param returns - status of function execution
300 */
301 int remoteproc_boot(struct remote_proc *rproc)
302 {
304 void *load_addr;
305 int status;
307 if (!rproc) {
308 return RPROC_ERR_PARAM;
309 }
311 /* Stop the remote CPU */
312 hil_shutdown_cpu(rproc->proc);
314 /* Load the firmware */
315 status = remoteproc_loader_load_remote_firmware(rproc->loader);
316 if (status == RPROC_SUCCESS) {
317 load_addr = remoteproc_get_load_address(rproc->loader);
318 if (load_addr != RPROC_ERR_PTR) {
319 /* Start the remote cpu */
320 status = hil_boot_cpu(rproc->proc,
321 (unsigned int)load_addr);
322 if (status == RPROC_SUCCESS) {
323 /* Wait for remote side to come up. This delay is arbitrary and may
324 * need adjustment for different configuration of remote systems */
325 env_sleep_msec(RPROC_BOOT_DELAY);
327 /* Initialize RPMSG "messaging" component */
329 /* It is a work-around to work with remote Linux context.
330 Since the upstream Linux rpmsg implementation always
331 assumes itself to be an rpmsg master, we initialize
332 the remote device as an rpmsg master for remote Linux
333 configuration only. */
334 #if defined (OPENAMP_REMOTE_LINUX_ENABLE)
335 status =
336 rpmsg_init(rproc->proc->cpu_id,
337 &rproc->rdev,
338 rproc->channel_created,
339 rproc->channel_destroyed,
340 rproc->default_cb, RPMSG_MASTER);
341 #else
342 status =
343 rpmsg_init(rproc->proc->cpu_id,
344 &rproc->rdev,
345 rproc->channel_created,
346 rproc->channel_destroyed,
347 rproc->default_cb, RPMSG_REMOTE);
348 #endif
349 }
350 } else {
351 status = RPROC_ERR_LOADER;
352 }
353 } else {
354 status = RPROC_ERR_LOADER;
355 }
357 return status;
358 }
360 /**
361 * remoteproc_shutdown
362 *
363 * This function shutdowns the remote execution context
364 *
365 * @param rproc - pointer to remote proc instance to shutdown
366 *
367 * @param returns - status of function execution
368 */
369 int remoteproc_shutdown(struct remote_proc *rproc)
370 {
372 if (rproc) {
373 if (rproc->rdev) {
374 rpmsg_deinit(rproc->rdev);
375 rproc->rdev = RPROC_NULL;
376 }
377 if (rproc->proc) {
378 hil_shutdown_cpu(rproc->proc);
379 }
380 }
382 return RPROC_SUCCESS;
383 }