ced4eef662e170e032c79123c992a8b0de4ad131
[processor-sdk/open-amp.git] / lib / remoteproc / remoteproc.c
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"
38 #include "metal/alloc.h"
39 #include "metal/sleep.h"
41 /**
42  * remoteproc_resource_init
43  *
44  * Initializes resources for remoteproc remote configuration. Only
45  * remoteproc remote applications are allowed to call this function.
46  *
47  * @param rsc_info          - pointer to resource table info control
48  *                                                        block
49  * @param proc              - pointer to the hil_proc
50  * @param channel_created   - callback function for channel creation
51  * @param channel_destroyed - callback function for channel deletion
52  * @param default_cb        - default callback for channel I/O
53  * @param rproc_handle      - pointer to new remoteproc instance
54  * @param rpmsg_role        - 1 for rpmsg master, or 0 for rpmsg slave
55  *
56  * @param returns - status of function execution
57  *
58  */
59 int remoteproc_resource_init(struct rsc_table_info *rsc_info,
60                              struct hil_proc *proc,
61                              rpmsg_chnl_cb_t channel_created,
62                              rpmsg_chnl_cb_t channel_destroyed,
63                              rpmsg_rx_cb_t default_cb,
64                              struct remote_proc **rproc_handle,
65                              int rpmsg_role)
66 {
68         struct remote_proc *rproc;
69         int status;
70         int remote_rpmsg_role;
72         if (!rsc_info || !proc) {
73                 return RPROC_ERR_PARAM;
74         }
76         rproc = metal_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 = proc;
82                 status = hil_init_proc(proc);
83                 if (!status) {
84                         /* Parse resource table */
85                         status =
86                             handle_rsc_table(rproc, rsc_info->rsc_tab,
87                                              rsc_info->size);
88                         if (status == RPROC_SUCCESS) {
89                                 /* Initialize RPMSG "messaging" component */
90                                 *rproc_handle = rproc;
91                                 remote_rpmsg_role = (rpmsg_role == RPMSG_MASTER?
92                                                 RPMSG_REMOTE : RPMSG_MASTER);
93                                 status =
94                                     rpmsg_init(proc,
95                                                &rproc->rdev, channel_created,
96                                                channel_destroyed, default_cb,
97                                                remote_rpmsg_role);
98                         } else {
99                                 status = RPROC_ERR_NO_RSC_TABLE;
100                         }
101                 } else {
102                         status = RPROC_ERR_CPU_INIT;
103                 }
104         } else {
105                 status = RPROC_ERR_NO_MEM;
106         }
108         /* Cleanup in case of error */
109         if (status != RPROC_SUCCESS) {
110                 *rproc_handle = 0;
111                 (void)remoteproc_resource_deinit(rproc);
112                 return status;
113         }
114         return status;
117 /**
118  * remoteproc_resource_deinit
119  *
120  * Uninitializes resources for remoteproc "remote" configuration.
121  *
122  * @param rproc - pointer to rproc instance
123  *
124  * @param returns - status of function execution
125  *
126  */
128 int remoteproc_resource_deinit(struct remote_proc *rproc)
130         if (rproc) {
131                 if (rproc->rdev) {
132                         rpmsg_deinit(rproc->rdev);
133                 }
134                 if (rproc->proc) {
135                         hil_delete_proc(rproc->proc);
136                         rproc->proc = NULL;
137                 }
138                 metal_free_memory(rproc);
139         }
141         return RPROC_SUCCESS;
144 /**
145  * remoteproc_init
146  *
147  * Initializes resources for remoteproc master configuration. Only
148  * remoteproc master applications are allowed to call this function.
149  *
150  * @param fw_name           - name of frimware
151  * @param proc              - pointer to hil_proc
152  * @param channel_created   - callback function for channel creation
153  * @param channel_destroyed - callback function for channel deletion
154  * @param default_cb        - default callback for channel I/O
155  * @param rproc_handle      - pointer to new remoteproc instance
156  *
157  * @param returns - status of function execution
158  *
159  */
160 int remoteproc_init(char *fw_name, struct hil_proc *proc,
161                     rpmsg_chnl_cb_t channel_created,
162                     rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb,
163                     struct remote_proc **rproc_handle)
166         struct remote_proc *rproc;
167         struct resource_table *rsc_table;
168         unsigned int fw_size, rsc_size;
169         uintptr_t fw_addr;
170         int status;
172         if (!fw_name) {
173                 return RPROC_ERR_PARAM;
174         }
176         rproc = metal_allocate_memory(sizeof(struct remote_proc));
177         if (rproc) {
178                 memset((void *)rproc, 0x00, sizeof(struct remote_proc));
179                 /* Create proc instance */
180                 status = hil_init_proc(proc);
181                 if (!status) {
182                         /* Retrieve firmware attributes */
183                         status =
184                             hil_get_firmware(fw_name, &fw_addr,
185                                              &fw_size);
186                         if (!status) {
187                                 /* Initialize ELF loader - currently only ELF format is supported */
188                                 rproc->loader =
189                                     remoteproc_loader_init(ELF_LOADER);
190                                 if (rproc->loader) {
191                                         /* Attach the given firmware with the ELF parser/loader */
192                                         status =
193                                             remoteproc_loader_attach_firmware
194                                             (rproc->loader,
195                                              (void *)fw_addr);
196                                 } else {
197                                         status = RPROC_ERR_LOADER;
198                                 }
199                         }
200                 } else {
201                         status = RPROC_ERR_CPU_INIT;
202                 }
203         } else {
204                 status = RPROC_ERR_NO_MEM;
205         }
207         if (!status) {
208                 rproc->role = RPROC_MASTER;
210                 /* Get resource table from firmware */
211                 rsc_table =
212                     remoteproc_loader_retrieve_resource_section(rproc->loader,
213                                                                 &rsc_size);
214                 if (rsc_table) {
215                         /* Parse resource table */
216                         status = handle_rsc_table(rproc, rsc_table, rsc_size);
217                 } else {
218                         status = RPROC_ERR_NO_RSC_TABLE;
219                 }
220         }
222         /* Cleanup in case of error */
223         if (status != RPROC_SUCCESS) {
224                 (void)remoteproc_deinit(rproc);
225                 return status;
226         }
228         rproc->channel_created = channel_created;
229         rproc->channel_destroyed = channel_destroyed;
230         rproc->default_cb = default_cb;
232         *rproc_handle = rproc;
234         return status;
237 /**
238  * remoteproc_deinit
239  *
240  * Uninitializes resources for remoteproc "master" configuration.
241  *
242  * @param rproc - pointer to remote proc instance
243  *
244  * @param returns - status of function execution
245  *
246  */
247 int remoteproc_deinit(struct remote_proc *rproc)
250         if (rproc) {
251                 if (rproc->loader) {
252                         (void)remoteproc_loader_delete(rproc->loader);
253                         rproc->loader = RPROC_NULL;
254                 }
255                 if (rproc->proc) {
256                         hil_delete_proc(rproc->proc);
257                         rproc->proc = RPROC_NULL;
258                 }
259                 metal_free_memory(rproc);
260         }
262         return RPROC_SUCCESS;
265 /**
266  * remoteproc_boot
267  *
268  * This function loads the image on the remote processor and starts
269  * its execution from image load address.
270  *
271  * @param rproc - pointer to remoteproc instance to boot
272  *
273  * @param returns - status of function execution
274  */
275 int remoteproc_boot(struct remote_proc *rproc)
278         void *load_addr;
279         int status;
281         if (!rproc) {
282                 return RPROC_ERR_PARAM;
283         }
285         /* Stop the remote CPU */
286         hil_shutdown_cpu(rproc->proc);
288         /* Load the firmware */
289         status = remoteproc_loader_load_remote_firmware(rproc->loader);
290         if (status == RPROC_SUCCESS) {
291                 load_addr = remoteproc_get_load_address(rproc->loader);
292                 if (load_addr != RPROC_ERR_PTR) {
293                         /* Start the remote cpu */
294                         status = hil_boot_cpu(rproc->proc,
295                                               (uintptr_t)load_addr);
296                         if (status == RPROC_SUCCESS) {
297                                 /* Wait for remote side to come up. This delay is arbitrary and may
298                                  * need adjustment for different configuration of remote systems */
299                                 metal_sleep_usec(RPROC_BOOT_DELAY);
301                                 /* Initialize RPMSG "messaging" component */
303                                 /* It is a work-around to work with remote Linux context. 
304                                    Since the upstream Linux rpmsg implementation always 
305                                    assumes itself to be an rpmsg master, we initialize
306                                    the remote device as an rpmsg master for remote Linux
307                                    configuration only. */
308 #if defined (OPENAMP_REMOTE_LINUX_ENABLE)
309                                 status =
310                                     rpmsg_init(rproc->proc,
311                                                &rproc->rdev,
312                                                rproc->channel_created,
313                                                rproc->channel_destroyed,
314                                                rproc->default_cb, RPMSG_MASTER);
315 #else
316                                 status =
317                                     rpmsg_init(rproc->proc,
318                                                &rproc->rdev,
319                                                rproc->channel_created,
320                                                rproc->channel_destroyed,
321                                                rproc->default_cb, RPMSG_REMOTE);
322 #endif
323                         }
324                 } else {
325                         status = RPROC_ERR_LOADER;
326                 }
327         } else {
328                 status = RPROC_ERR_LOADER;
329         }
331         return status;
334 /**
335  * remoteproc_shutdown
336  *
337  * This function shutdowns the remote execution context
338  *
339  * @param rproc - pointer to remote proc instance to shutdown
340  *
341  * @param returns - status of function execution
342  */
343 int remoteproc_shutdown(struct remote_proc *rproc)
346         if (rproc) {
347                 if (rproc->proc) {
348                         hil_shutdown_cpu(rproc->proc);
349                 }
350                 if (rproc->rdev) {
351                         rpmsg_deinit(rproc->rdev);
352                         rproc->rdev = RPROC_NULL;
353                         rproc->proc = RPROC_NULL;
354                 }
355         }
357         return RPROC_SUCCESS;