406532214b1f20766fe469e368a8fc352f4c2eb2
[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                 metal_free_memory(rproc);
135         }
137         return RPROC_SUCCESS;
140 /**
141  * remoteproc_init
142  *
143  * Initializes resources for remoteproc master configuration. Only
144  * remoteproc master applications are allowed to call this function.
145  *
146  * @param fw_name           - name of frimware
147  * @param proc              - pointer to hil_proc
148  * @param channel_created   - callback function for channel creation
149  * @param channel_destroyed - callback function for channel deletion
150  * @param default_cb        - default callback for channel I/O
151  * @param rproc_handle      - pointer to new remoteproc instance
152  *
153  * @param returns - status of function execution
154  *
155  */
156 int remoteproc_init(char *fw_name, struct hil_proc *proc,
157                     rpmsg_chnl_cb_t channel_created,
158                     rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb,
159                     struct remote_proc **rproc_handle)
162         struct remote_proc *rproc;
163         struct resource_table *rsc_table;
164         unsigned int fw_size, rsc_size;
165         uintptr_t fw_addr;
166         int status;
168         if (!fw_name) {
169                 return RPROC_ERR_PARAM;
170         }
172         rproc = metal_allocate_memory(sizeof(struct remote_proc));
173         if (rproc) {
174                 memset((void *)rproc, 0x00, sizeof(struct remote_proc));
175                 /* Create proc instance */
176                 status = hil_init_proc(proc);
177                 if (!status) {
178                         /* Retrieve firmware attributes */
179                         status =
180                             hil_get_firmware(fw_name, &fw_addr,
181                                              &fw_size);
182                         if (!status) {
183                                 /* Initialize ELF loader - currently only ELF format is supported */
184                                 rproc->loader =
185                                     remoteproc_loader_init(ELF_LOADER);
186                                 if (rproc->loader) {
187                                         /* Attach the given firmware with the ELF parser/loader */
188                                         status =
189                                             remoteproc_loader_attach_firmware
190                                             (rproc->loader,
191                                              (void *)fw_addr);
192                                 } else {
193                                         status = RPROC_ERR_LOADER;
194                                 }
195                         }
196                 } else {
197                         status = RPROC_ERR_CPU_INIT;
198                 }
199         } else {
200                 status = RPROC_ERR_NO_MEM;
201         }
203         if (!status) {
204                 rproc->role = RPROC_MASTER;
206                 /* Get resource table from firmware */
207                 rsc_table =
208                     remoteproc_loader_retrieve_resource_section(rproc->loader,
209                                                                 &rsc_size);
210                 if (rsc_table) {
211                         /* Parse resource table */
212                         status = handle_rsc_table(rproc, rsc_table, rsc_size);
213                 } else {
214                         status = RPROC_ERR_NO_RSC_TABLE;
215                 }
216         }
218         /* Cleanup in case of error */
219         if (status != RPROC_SUCCESS) {
220                 (void)remoteproc_deinit(rproc);
221                 return status;
222         }
224         rproc->channel_created = channel_created;
225         rproc->channel_destroyed = channel_destroyed;
226         rproc->default_cb = default_cb;
228         *rproc_handle = rproc;
230         return status;
233 /**
234  * remoteproc_deinit
235  *
236  * Uninitializes resources for remoteproc "master" configuration.
237  *
238  * @param rproc - pointer to remote proc instance
239  *
240  * @param returns - status of function execution
241  *
242  */
243 int remoteproc_deinit(struct remote_proc *rproc)
246         if (rproc) {
247                 if (rproc->loader) {
248                         (void)remoteproc_loader_delete(rproc->loader);
249                         rproc->loader = RPROC_NULL;
250                 }
251                 if (rproc->proc) {
252                         hil_delete_proc(rproc->proc);
253                         rproc->proc = RPROC_NULL;
254                 }
255                 metal_free_memory(rproc);
256         }
258         return RPROC_SUCCESS;
261 /**
262  * remoteproc_boot
263  *
264  * This function loads the image on the remote processor and starts
265  * its execution from image load address.
266  *
267  * @param rproc - pointer to remoteproc instance to boot
268  *
269  * @param returns - status of function execution
270  */
271 int remoteproc_boot(struct remote_proc *rproc)
274         void *load_addr;
275         int status;
277         if (!rproc) {
278                 return RPROC_ERR_PARAM;
279         }
281         /* Stop the remote CPU */
282         hil_shutdown_cpu(rproc->proc);
284         /* Load the firmware */
285         status = remoteproc_loader_load_remote_firmware(rproc->loader);
286         if (status == RPROC_SUCCESS) {
287                 load_addr = remoteproc_get_load_address(rproc->loader);
288                 if (load_addr != RPROC_ERR_PTR) {
289                         /* Start the remote cpu */
290                         status = hil_boot_cpu(rproc->proc,
291                                               (uintptr_t)load_addr);
292                         if (status == RPROC_SUCCESS) {
293                                 /* Wait for remote side to come up. This delay is arbitrary and may
294                                  * need adjustment for different configuration of remote systems */
295                                 metal_sleep_usec(RPROC_BOOT_DELAY);
297                                 /* Initialize RPMSG "messaging" component */
299                                 /* It is a work-around to work with remote Linux context. 
300                                    Since the upstream Linux rpmsg implementation always 
301                                    assumes itself to be an rpmsg master, we initialize
302                                    the remote device as an rpmsg master for remote Linux
303                                    configuration only. */
304 #if defined (OPENAMP_REMOTE_LINUX_ENABLE)
305                                 status =
306                                     rpmsg_init(rproc->proc,
307                                                &rproc->rdev,
308                                                rproc->channel_created,
309                                                rproc->channel_destroyed,
310                                                rproc->default_cb, RPMSG_MASTER);
311 #else
312                                 status =
313                                     rpmsg_init(rproc->proc,
314                                                &rproc->rdev,
315                                                rproc->channel_created,
316                                                rproc->channel_destroyed,
317                                                rproc->default_cb, RPMSG_REMOTE);
318 #endif
319                         }
320                 } else {
321                         status = RPROC_ERR_LOADER;
322                 }
323         } else {
324                 status = RPROC_ERR_LOADER;
325         }
327         return status;
330 /**
331  * remoteproc_shutdown
332  *
333  * This function shutdowns the remote execution context
334  *
335  * @param rproc - pointer to remote proc instance to shutdown
336  *
337  * @param returns - status of function execution
338  */
339 int remoteproc_shutdown(struct remote_proc *rproc)
342         if (rproc) {
343                 if (rproc->proc) {
344                         hil_shutdown_cpu(rproc->proc);
345                 }
346                 if (rproc->rdev) {
347                         rpmsg_deinit(rproc->rdev);
348                         rproc->rdev = RPROC_NULL;
349                         rproc->proc = RPROC_NULL;
350                 }
351         }
353         return RPROC_SUCCESS;