f933bdafa166fdb4d50908103eeccf3b26e180a8
[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"
40 /**
41  * remoteproc_resource_init
42  *
43  * Initializes resources for remoteproc remote configuration. Only
44  * remoteproc remote applications are allowed to call this function.
45  *
46  * @param rsc_info          - pointer to resource table info control
47  *                                                        block
48  * @param pdata             - platform data for remote processor
49  * @param channel_created   - callback function for channel creation
50  * @param channel_destroyed - callback function for channel deletion
51  * @param default_cb        - default callback for channel I/O
52  * @param rproc_handle      - pointer to new remoteproc instance
53  * @param rpmsg_role        - 1 for rpmsg master, or 0 for rpmsg slave
54  *
55  * @param returns - status of function execution
56  *
57  */
58 int remoteproc_resource_init(struct rsc_table_info *rsc_info,
59                              void *pdata,
60                              rpmsg_chnl_cb_t channel_created,
61                              rpmsg_chnl_cb_t channel_destroyed,
62                              rpmsg_rx_cb_t default_cb,
63                              struct remote_proc **rproc_handle,
64                              int rpmsg_role)
65 {
67         struct remote_proc *rproc;
68         int status;
69         int remote_rpmsg_role;
71         if (!rsc_info) {
72                 return RPROC_ERR_PARAM;
73         }
75         rproc = metal_allocate_memory(sizeof(struct remote_proc));
76         if (rproc) {
77                 memset(rproc, 0x00, sizeof(struct remote_proc));
78                 /* There can be only one master for remote configuration so use the
79                  * rsvd cpu id for creating hil proc */
80                 rproc->proc = hil_create_proc(pdata, HIL_RSVD_CPU_ID);
81                 if (rproc->proc) {
82                         /* Parse resource table */
83                         status =
84                             handle_rsc_table(rproc, rsc_info->rsc_tab,
85                                              rsc_info->size);
86                         if (status == RPROC_SUCCESS) {
87                                 /* Initialize RPMSG "messaging" component */
88                                 *rproc_handle = rproc;
89                                 remote_rpmsg_role = (rpmsg_role == RPMSG_MASTER?
90                                                 RPMSG_REMOTE : RPMSG_MASTER);
91                                 status =
92                                     rpmsg_init(NULL, rproc->proc->cpu_id,
93                                                &rproc->rdev, channel_created,
94                                                channel_destroyed, default_cb,
95                                                remote_rpmsg_role);
96                         } else {
97                                 status = RPROC_ERR_NO_RSC_TABLE;
98                         }
99                 } else {
100                         status = RPROC_ERR_CPU_ID;
101                 }
102         } else {
103                 status = RPROC_ERR_NO_MEM;
104         }
106         /* Cleanup in case of error */
107         if (status != RPROC_SUCCESS) {
108                 *rproc_handle = 0;
109                 (void)remoteproc_resource_deinit(rproc);
110                 return status;
111         }
112         return status;
115 /**
116  * remoteproc_resource_deinit
117  *
118  * Uninitializes resources for remoteproc "remote" configuration.
119  *
120  * @param rproc - pointer to rproc instance
121  *
122  * @param returns - status of function execution
123  *
124  */
126 int remoteproc_resource_deinit(struct remote_proc *rproc)
128         if (rproc) {
129                 if (rproc->rdev) {
130                         rpmsg_deinit(rproc->rdev);
131                 }
132                 metal_free_memory(rproc);
133         }
135         return RPROC_SUCCESS;
138 /**
139  * remoteproc_init
140  *
141  * Initializes resources for remoteproc master configuration. Only
142  * remoteproc master applications are allowed to call this function.
143  *
144  * @param fw_name           - name of frimware
145  * @param pdata             - platform data for remote processor
146  * @param channel_created   - callback function for channel creation
147  * @param channel_destroyed - callback function for channel deletion
148  * @param default_cb        - default callback for channel I/O
149  * @param rproc_handle      - pointer to new remoteproc instance
150  *
151  * @param returns - status of function execution
152  *
153  */
154 int remoteproc_init(char *fw_name, void *pdata,
155                     rpmsg_chnl_cb_t channel_created,
156                     rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb,
157                     struct remote_proc **rproc_handle)
160         struct remote_proc *rproc;
161         struct resource_table *rsc_table;
162         unsigned int fw_size, rsc_size;
163         uintptr_t fw_addr;
164         int status;
166         if (!fw_name) {
167                 return RPROC_ERR_PARAM;
168         }
170         rproc = metal_allocate_memory(sizeof(struct remote_proc));
171         if (rproc) {
172                 memset((void *)rproc, 0x00, sizeof(struct remote_proc));
173                 /* Create proc instance */
174                 rproc->proc = hil_create_proc(pdata, HIL_RSVD_CPU_ID);
175                 if (rproc->proc) {
176                         /* Retrieve firmware attributes */
177                         status =
178                             hil_get_firmware(fw_name, &fw_addr,
179                                              &fw_size);
180                         if (!status) {
181                                 /* Initialize ELF loader - currently only ELF format is supported */
182                                 rproc->loader =
183                                     remoteproc_loader_init(ELF_LOADER);
184                                 if (rproc->loader) {
185                                         /* Attach the given firmware with the ELF parser/loader */
186                                         status =
187                                             remoteproc_loader_attach_firmware
188                                             (rproc->loader,
189                                              (void *)fw_addr);
190                                 } else {
191                                         status = RPROC_ERR_LOADER;
192                                 }
193                         }
194                 } else {
195                         status = RPROC_ERR_NO_MEM;
196                 }
197         } else {
198                 status = RPROC_ERR_NO_MEM;
199         }
201         if (!status) {
202                 rproc->role = RPROC_MASTER;
204                 /* Get resource table from firmware */
205                 rsc_table =
206                     remoteproc_loader_retrieve_resource_section(rproc->loader,
207                                                                 &rsc_size);
208                 if (rsc_table) {
209                         /* Parse resource table */
210                         status = handle_rsc_table(rproc, rsc_table, rsc_size);
211                 } else {
212                         status = RPROC_ERR_NO_RSC_TABLE;
213                 }
214         }
216         /* Cleanup in case of error */
217         if (status != RPROC_SUCCESS) {
218                 (void)remoteproc_deinit(rproc);
219                 return status;
220         }
222         rproc->channel_created = channel_created;
223         rproc->channel_destroyed = channel_destroyed;
224         rproc->default_cb = default_cb;
226         *rproc_handle = rproc;
228         return status;
231 /**
232  * remoteproc_deinit
233  *
234  * Uninitializes resources for remoteproc "master" configuration.
235  *
236  * @param rproc - pointer to remote proc instance
237  *
238  * @param returns - status of function execution
239  *
240  */
241 int remoteproc_deinit(struct remote_proc *rproc)
244         if (rproc) {
245                 if (rproc->loader) {
246                         (void)remoteproc_loader_delete(rproc->loader);
247                         rproc->loader = RPROC_NULL;
248                 }
249                 if (rproc->proc) {
250                         hil_delete_proc(rproc->proc);
251                         rproc->proc = RPROC_NULL;
252                 }
253                 metal_free_memory(rproc);
254         }
256         return RPROC_SUCCESS;
259 /**
260  * remoteproc_boot
261  *
262  * This function loads the image on the remote processor and starts
263  * its execution from image load address.
264  *
265  * @param rproc - pointer to remoteproc instance to boot
266  *
267  * @param returns - status of function execution
268  */
269 int remoteproc_boot(struct remote_proc *rproc)
272         void *load_addr;
273         int status;
275         if (!rproc) {
276                 return RPROC_ERR_PARAM;
277         }
279         /* Stop the remote CPU */
280         hil_shutdown_cpu(rproc->proc);
282         /* Load the firmware */
283         status = remoteproc_loader_load_remote_firmware(rproc->loader);
284         if (status == RPROC_SUCCESS) {
285                 load_addr = remoteproc_get_load_address(rproc->loader);
286                 if (load_addr != RPROC_ERR_PTR) {
287                         /* Start the remote cpu */
288                         status = hil_boot_cpu(rproc->proc,
289                                               (uintptr_t)load_addr);
290                         if (status == RPROC_SUCCESS) {
291                                 /* Wait for remote side to come up. This delay is arbitrary and may
292                                  * need adjustment for different configuration of remote systems */
293                                 env_sleep_msec(RPROC_BOOT_DELAY);
295                                 /* Initialize RPMSG "messaging" component */
297                                 /* It is a work-around to work with remote Linux context. 
298                                    Since the upstream Linux rpmsg implementation always 
299                                    assumes itself to be an rpmsg master, we initialize
300                                    the remote device as an rpmsg master for remote Linux
301                                    configuration only. */
302 #if defined (OPENAMP_REMOTE_LINUX_ENABLE)
303                                 status =
304                                     rpmsg_init(NULL, rproc->proc->cpu_id,
305                                                &rproc->rdev,
306                                                rproc->channel_created,
307                                                rproc->channel_destroyed,
308                                                rproc->default_cb, RPMSG_MASTER);
309 #else
310                                 status =
311                                     rpmsg_init(NULL, rproc->proc->cpu_id,
312                                                &rproc->rdev,
313                                                rproc->channel_created,
314                                                rproc->channel_destroyed,
315                                                rproc->default_cb, RPMSG_REMOTE);
316 #endif
317                         }
318                 } else {
319                         status = RPROC_ERR_LOADER;
320                 }
321         } else {
322                 status = RPROC_ERR_LOADER;
323         }
325         return status;
328 /**
329  * remoteproc_shutdown
330  *
331  * This function shutdowns the remote execution context
332  *
333  * @param rproc - pointer to remote proc instance to shutdown
334  *
335  * @param returns - status of function execution
336  */
337 int remoteproc_shutdown(struct remote_proc *rproc)
340         if (rproc) {
341                 if (rproc->proc) {
342                         hil_shutdown_cpu(rproc->proc);
343                 }
344                 if (rproc->rdev) {
345                         rpmsg_deinit(rproc->rdev);
346                         rproc->rdev = RPROC_NULL;
347                         rproc->proc = RPROC_NULL;
348                 }
349         }
351         return RPROC_SUCCESS;