建立工程,成功创建两个虚拟串口
This commit is contained in:
32
source/OpenAMP/open-amp/apps/examples/load_fw/CMakeLists.txt
Normal file
32
source/OpenAMP/open-amp/apps/examples/load_fw/CMakeLists.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
set (_cflags "${CMAKE_C_FLAGS} ${APP_EXTRA_C_FLAGS}")
|
||||
set (_fw_dir "${APPS_SHARE_DIR}")
|
||||
|
||||
collector_list (_list PROJECT_INC_DIRS)
|
||||
collector_list (_app_list APP_INC_DIRS)
|
||||
include_directories (${_list} ${_app_list} ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
collector_list (_list PROJECT_LIB_DIRS)
|
||||
collector_list (_app_list APP_LIB_DIRS)
|
||||
link_directories (${_list} ${_app_list})
|
||||
|
||||
get_property (_linker_opt GLOBAL PROPERTY APP_LINKER_OPT)
|
||||
collector_list (_deps PROJECT_LIB_DEPS)
|
||||
|
||||
set (OPENAMP_LIB open_amp)
|
||||
|
||||
foreach (_app load_fw)
|
||||
collector_list (_sources APP_COMMON_SOURCES)
|
||||
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/${_app}.c")
|
||||
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/mem_image_store.c")
|
||||
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/zynqmp_r5_lcm_rproc_example.c")
|
||||
|
||||
if (WITH_STATIC_LIB)
|
||||
add_executable (${_app}.out ${_sources})
|
||||
set_source_files_properties(${_sources} PROPERTIES COMPILE_FLAGS "${_cflags}")
|
||||
|
||||
target_link_libraries(${_app}.out -Wl,-Map=${_app}.map -Wl,--gc-sections -T"${CMAKE_CURRENT_SOURCE_DIR}/lscript.ld" -Wl,--start-group ${OPENAMP_LIB}-static -lxilpm ${_deps} -Wl,--end-group)
|
||||
|
||||
install (TARGETS ${_app}.out RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif (WITH_STATIC_LIB)
|
||||
endforeach(_app)
|
||||
250
source/OpenAMP/open-amp/apps/examples/load_fw/load_fw.c
Normal file
250
source/OpenAMP/open-amp/apps/examples/load_fw/load_fw.c
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Load firmware example
|
||||
*
|
||||
* Copyright(c) 2018 Xilinx Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <metal/io.h>
|
||||
#include <metal/sys.h>
|
||||
#include <openamp/remoteproc.h>
|
||||
#include <openamp/remoteproc_loader.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
/* Xilinx headers */
|
||||
#include <pm_api_sys.h>
|
||||
#include <pm_defs.h>
|
||||
#include <xil_printf.h>
|
||||
|
||||
#define LPRINTF(format, ...) xil_printf(format, ##__VA_ARGS__)
|
||||
//#define LPRINTF(format, ...)
|
||||
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
|
||||
|
||||
extern struct remoteproc_ops r5_rproc_ops;
|
||||
extern struct image_store_ops mem_image_store_ops;
|
||||
|
||||
struct mem_file {
|
||||
const void *base;
|
||||
};
|
||||
|
||||
static struct mem_file image = {
|
||||
.base = (void *)0x3ED00000,
|
||||
};
|
||||
|
||||
static XIpiPsu IpiInst;
|
||||
|
||||
static XStatus IpiConfigure(XIpiPsu *const IpiInstPtr)
|
||||
{
|
||||
XStatus Status;
|
||||
XIpiPsu_Config *IpiCfgPtr;
|
||||
|
||||
/* Look Up the config data */
|
||||
IpiCfgPtr = XIpiPsu_LookupConfig(XPAR_XIPIPSU_0_DEVICE_ID);
|
||||
if (NULL == IpiCfgPtr) {
|
||||
Status = XST_FAILURE;
|
||||
LPERROR("%s ERROR in getting CfgPtr\n", __func__);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Init with the Cfg Data */
|
||||
Status = XIpiPsu_CfgInitialize(IpiInstPtr, IpiCfgPtr,
|
||||
IpiCfgPtr->BaseAddress);
|
||||
if (XST_SUCCESS != Status) {
|
||||
LPERROR("%s ERROR #%d in configuring IPI\n", __func__, Status);
|
||||
return Status;
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
static void app_log_handler(enum metal_log_level level,
|
||||
const char *format, ...)
|
||||
{
|
||||
char msg[1024];
|
||||
va_list args;
|
||||
static const char *level_strs[] = {
|
||||
"metal: emergency: ",
|
||||
"metal: alert: ",
|
||||
"metal: critical: ",
|
||||
"metal: error: ",
|
||||
"metal: warning: ",
|
||||
"metal: notice: ",
|
||||
"metal: info: ",
|
||||
"metal: debug: ",
|
||||
};
|
||||
|
||||
va_start(args, format);
|
||||
vsnprintf(msg, sizeof(msg), format, args);
|
||||
va_end(args);
|
||||
|
||||
if (level <= METAL_LOG_EMERGENCY || level > METAL_LOG_DEBUG)
|
||||
level = METAL_LOG_EMERGENCY;
|
||||
|
||||
xil_printf("%s%s", level_strs[level], msg);
|
||||
}
|
||||
|
||||
int load_exectuable_block(struct remoteproc *rproc,
|
||||
struct image_store_ops *store_ops, void *store,
|
||||
const char *img_path)
|
||||
{
|
||||
int ret;
|
||||
|
||||
(void)img_path;
|
||||
if (rproc == NULL)
|
||||
return -EINVAL;
|
||||
/* Configure remoteproc to get ready to load executable */
|
||||
remoteproc_config(rproc, NULL);
|
||||
/* Load remoteproc executable */
|
||||
LPRINTF("Start to load executable with remoteproc_load() \r\n");
|
||||
ret = remoteproc_load(rproc, NULL, store, store_ops, NULL);
|
||||
if (ret) {
|
||||
LPRINTF("failed to load firmware\r\n");
|
||||
return ret;
|
||||
}
|
||||
/* Start the processor */
|
||||
ret = remoteproc_start(rproc);
|
||||
if (ret) {
|
||||
LPRINTF("failed to start processor\r\n");
|
||||
return ret;
|
||||
}
|
||||
LPRINTF("successfully started the processor\r\n");
|
||||
/* ... */
|
||||
asm volatile("wfi");
|
||||
LPRINTF("going to stop the processor\r\n");
|
||||
remoteproc_stop(rproc);
|
||||
/* application may want to do some cleanup before shutdown */
|
||||
LPRINTF("going to shutdown the processor\r\n");
|
||||
remoteproc_shutdown(rproc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_exectuable_noblock(struct remoteproc *rproc,
|
||||
struct image_store_ops *store_ops, void *store,
|
||||
const char *img_path)
|
||||
{
|
||||
int ret;
|
||||
const void *img_data;
|
||||
void *img_info = NULL;
|
||||
metal_phys_addr_t pa;
|
||||
struct metal_io_region *io;
|
||||
size_t offset, noffset;
|
||||
size_t len, nlen, nmlen;
|
||||
unsigned char padding;
|
||||
|
||||
if (rproc == NULL)
|
||||
return -EINVAL;
|
||||
/* Configure remoteproc to get ready to load executable */
|
||||
remoteproc_config(rproc, NULL);
|
||||
/* Load remoteproc executable */
|
||||
LPRINTF("Start to load executable with remoteproc_load() \r\n");
|
||||
ret = store_ops->open(store, img_path, &img_data);
|
||||
if (ret <= 0)
|
||||
return -EINVAL;
|
||||
offset = 0;
|
||||
len = (size_t)ret;
|
||||
do {
|
||||
nlen = 0;
|
||||
pa = METAL_BAD_PHYS;
|
||||
io = NULL;
|
||||
nmlen = 0;
|
||||
LPRINTF("%s, loading 0x%lx,0x%lx\r\n",
|
||||
__func__, offset, len);
|
||||
ret = remoteproc_load_noblock(rproc, img_data, offset, len,
|
||||
&img_info, &pa, &io, &noffset,
|
||||
&nlen, &nmlen, &padding);
|
||||
if (ret) {
|
||||
LPERROR("failed to load executable, 0x%lx,0x%lx\r\n",
|
||||
offset, len);
|
||||
return ret;
|
||||
}
|
||||
if (nlen == 0)
|
||||
break;
|
||||
offset = noffset;
|
||||
len = nlen;
|
||||
ret = store_ops->load(store, noffset, nlen, &img_data, pa,
|
||||
io, 1);
|
||||
if (ret != (int)nlen) {
|
||||
LPERROR("failed to load data to memory, 0x%lx,0x%lx\r\n",
|
||||
noffset, nlen);
|
||||
return ret;
|
||||
}
|
||||
if (nmlen > nlen && io != NULL) {
|
||||
/* pad the rest of the memory with 0 */
|
||||
size_t tmpoffset;
|
||||
|
||||
tmpoffset = metal_io_phys_to_offset(io, pa + nlen);
|
||||
metal_io_block_set(io, tmpoffset, padding,
|
||||
(nmlen - nlen));
|
||||
|
||||
}
|
||||
} while(1);
|
||||
|
||||
/* Start the processor */
|
||||
ret = remoteproc_start(rproc);
|
||||
if (ret) {
|
||||
LPRINTF("failed to start processor\r\n");
|
||||
return ret;
|
||||
}
|
||||
LPRINTF("successfully started the processor\r\n");
|
||||
/* ... */
|
||||
asm volatile("wfi");
|
||||
LPRINTF("going to stop the processor\r\n");
|
||||
remoteproc_stop(rproc);
|
||||
/* application may want to do some cleanup before shutdown */
|
||||
LPRINTF("going to shutdown the processor\r\n");
|
||||
remoteproc_shutdown(rproc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct remoteproc rproc;
|
||||
struct remoteproc *ret_rproc;
|
||||
void *store = ℑ
|
||||
unsigned int cpu_id = NODE_RPU_1;
|
||||
int ret;
|
||||
struct metal_init_params metal_param = {
|
||||
.log_handler = app_log_handler,
|
||||
.log_level = METAL_LOG_DEBUG,
|
||||
};
|
||||
|
||||
if (XST_SUCCESS != IpiConfigure(&IpiInst)) {
|
||||
LPERROR("Failed to config IPI instance\r\n");
|
||||
return -1;
|
||||
}
|
||||
if (XST_SUCCESS != XPm_InitXilpm(&IpiInst)) {
|
||||
LPERROR("Failed to initialize PM\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LPRINTF("Loading Exectuable Demo\n");
|
||||
/* Initialize libmetal evironment */
|
||||
metal_init(&metal_param);
|
||||
/* Initialize remoteproc instance */
|
||||
ret_rproc = remoteproc_init(&rproc, &r5_rproc_ops, &cpu_id);
|
||||
if (!ret_rproc) {
|
||||
LPRINTF("failed to initialize coprocessor\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = load_exectuable_block(&rproc, &mem_image_store_ops, store, NULL);
|
||||
if (ret < 0) {
|
||||
LPERROR("load_exectuable_block failed\r\n");
|
||||
/* Make sure the remote is shut down */
|
||||
remoteproc_shutdown(&rproc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = load_exectuable_noblock(&rproc, &mem_image_store_ops, store,
|
||||
NULL);
|
||||
if (ret < 0) {
|
||||
LPERROR("load_exectuable_noblock failed\r\n");
|
||||
/* Make sure the remote is shut down */
|
||||
remoteproc_shutdown(&rproc);
|
||||
return -1;
|
||||
}
|
||||
remoteproc_remove(&rproc);
|
||||
return ret;
|
||||
}
|
||||
315
source/OpenAMP/open-amp/apps/examples/load_fw/lscript.ld
Normal file
315
source/OpenAMP/open-amp/apps/examples/load_fw/lscript.ld
Normal file
@@ -0,0 +1,315 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Xilinx, Inc. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of the Xilinx shall not be used
|
||||
* in advertising or otherwise to promote the sale, use or other dealings in
|
||||
* this Software without prior written authorization from Xilinx.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000;
|
||||
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x4000;
|
||||
|
||||
_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
|
||||
_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
|
||||
_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024;
|
||||
_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
|
||||
_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;
|
||||
|
||||
/* Define Memories in the system */
|
||||
/* TCM size is set to 2*0x20000 for R5 in lockstep mode */
|
||||
MEMORY
|
||||
{
|
||||
psu_ocm_ram_1_S_AXI_BASEADDR : ORIGIN = 0xFFFF0000, LENGTH = 0x00010000
|
||||
psu_r5_tcm_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00000000, LENGTH = 0x00010000
|
||||
psu_r5_tcm_ram_1_S_AXI_BASEADDR : ORIGIN = 0x00020000, LENGTH = 0x00010000
|
||||
}
|
||||
|
||||
/* Specify the default entry point to the program */
|
||||
|
||||
/* ENTRY(_boot) */
|
||||
|
||||
ENTRY(_vector_table)
|
||||
|
||||
/* Define the sections, and where they are mapped in memory */
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.vectors : {
|
||||
KEEP (*(.vectors))
|
||||
*(.boot)
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.text : {
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.gnu.linkonce.t.*)
|
||||
*(.plt)
|
||||
*(.gnu_warning)
|
||||
*(.gcc_execpt_table)
|
||||
*(.glue_7)
|
||||
*(.glue_7t)
|
||||
*(.vfp11_veneer)
|
||||
*(.ARM.extab)
|
||||
*(.gnu.linkonce.armextab.*)
|
||||
} > psu_r5_tcm_ram_1_S_AXI_BASEADDR
|
||||
|
||||
.init : {
|
||||
KEEP (*(.init))
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.fini : {
|
||||
KEEP (*(.fini))
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.interp : {
|
||||
KEEP (*(.interp))
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.note-ABI-tag : {
|
||||
KEEP (*(.note-ABI-tag))
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.rodata : {
|
||||
__rodata_start = .;
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.gnu.linkonce.r.*)
|
||||
__rodata_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.rodata1 : {
|
||||
__rodata1_start = .;
|
||||
*(.rodata1)
|
||||
*(.rodata1.*)
|
||||
__rodata1_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.sdata2 : {
|
||||
__sdata2_start = .;
|
||||
*(.sdata2)
|
||||
*(.sdata2.*)
|
||||
*(.gnu.linkonce.s2.*)
|
||||
__sdata2_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.sbss2 : {
|
||||
__sbss2_start = .;
|
||||
*(.sbss2)
|
||||
*(.sbss2.*)
|
||||
*(.gnu.linkonce.sb2.*)
|
||||
__sbss2_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.data : {
|
||||
__data_start = .;
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
*(.gnu.linkonce.d.*)
|
||||
*(.jcr)
|
||||
*(.got)
|
||||
*(.got.plt)
|
||||
__data_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.data1 : {
|
||||
__data1_start = .;
|
||||
*(.data1)
|
||||
*(.data1.*)
|
||||
__data1_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.got : {
|
||||
*(.got)
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.ctors : {
|
||||
__CTOR_LIST__ = .;
|
||||
___CTORS_LIST___ = .;
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
__CTOR_END__ = .;
|
||||
___CTORS_END___ = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.dtors : {
|
||||
__DTOR_LIST__ = .;
|
||||
___DTORS_LIST___ = .;
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
__DTOR_END__ = .;
|
||||
___DTORS_END___ = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.fixup : {
|
||||
__fixup_start = .;
|
||||
*(.fixup)
|
||||
__fixup_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.eh_frame : {
|
||||
*(.eh_frame)
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.eh_framehdr : {
|
||||
__eh_framehdr_start = .;
|
||||
*(.eh_framehdr)
|
||||
__eh_framehdr_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.gcc_except_table : {
|
||||
*(.gcc_except_table)
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.mmu_tbl (ALIGN(16384)) : {
|
||||
__mmu_tbl_start = .;
|
||||
*(.mmu_tbl)
|
||||
__mmu_tbl_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.ARM.exidx : {
|
||||
__exidx_start = .;
|
||||
*(.ARM.exidx*)
|
||||
*(.gnu.linkonce.armexidix.*.*)
|
||||
__exidx_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.preinit_array : {
|
||||
__preinit_array_start = .;
|
||||
KEEP (*(SORT(.preinit_array.*)))
|
||||
KEEP (*(.preinit_array))
|
||||
__preinit_array_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.init_array : {
|
||||
__init_array_start = .;
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
__init_array_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.fini_array : {
|
||||
__fini_array_start = .;
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
KEEP (*(.fini_array))
|
||||
__fini_array_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.ARM.attributes : {
|
||||
__ARM.attributes_start = .;
|
||||
*(.ARM.attributes)
|
||||
__ARM.attributes_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.sdata : {
|
||||
__sdata_start = .;
|
||||
*(.sdata)
|
||||
*(.sdata.*)
|
||||
*(.gnu.linkonce.s.*)
|
||||
__sdata_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.sbss (NOLOAD) : {
|
||||
__sbss_start = .;
|
||||
*(.sbss)
|
||||
*(.sbss.*)
|
||||
*(.gnu.linkonce.sb.*)
|
||||
__sbss_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.tdata : {
|
||||
__tdata_start = .;
|
||||
*(.tdata)
|
||||
*(.tdata.*)
|
||||
*(.gnu.linkonce.td.*)
|
||||
__tdata_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.tbss : {
|
||||
__tbss_start = .;
|
||||
*(.tbss)
|
||||
*(.tbss.*)
|
||||
*(.gnu.linkonce.tb.*)
|
||||
__tbss_end = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.bss (NOLOAD) : {
|
||||
. = ALIGN(4);
|
||||
__bss_start__ = .;
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
__bss_end__ = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 );
|
||||
|
||||
_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );
|
||||
|
||||
/* Generate Stack and Heap definitions */
|
||||
|
||||
.heap (NOLOAD) : {
|
||||
. = ALIGN(16);
|
||||
_heap = .;
|
||||
HeapBase = .;
|
||||
_heap_start = .;
|
||||
. += _HEAP_SIZE;
|
||||
_heap_end = .;
|
||||
HeapLimit = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
.stack (NOLOAD) : {
|
||||
. = ALIGN(16);
|
||||
_stack_end = .;
|
||||
. += _STACK_SIZE;
|
||||
_stack = .;
|
||||
__stack = _stack;
|
||||
. = ALIGN(16);
|
||||
_irq_stack_end = .;
|
||||
. += _IRQ_STACK_SIZE;
|
||||
__irq_stack = .;
|
||||
_supervisor_stack_end = .;
|
||||
. += _SUPERVISOR_STACK_SIZE;
|
||||
. = ALIGN(16);
|
||||
__supervisor_stack = .;
|
||||
_abort_stack_end = .;
|
||||
. += _ABORT_STACK_SIZE;
|
||||
. = ALIGN(16);
|
||||
__abort_stack = .;
|
||||
_fiq_stack_end = .;
|
||||
. += _FIQ_STACK_SIZE;
|
||||
. = ALIGN(16);
|
||||
__fiq_stack = .;
|
||||
_undef_stack_end = .;
|
||||
. += _UNDEF_STACK_SIZE;
|
||||
. = ALIGN(16);
|
||||
__undef_stack = .;
|
||||
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
|
||||
|
||||
_end = .;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Memory based image store Operation
|
||||
*
|
||||
* Copyright(c) 2018 Xilinx Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <metal/io.h>
|
||||
#include <metal/sys.h>
|
||||
#include <openamp/remoteproc_loader.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
/* Xilinx headers */
|
||||
#include <pm_api_sys.h>
|
||||
#include <pm_defs.h>
|
||||
#include <xil_printf.h>
|
||||
|
||||
#define LPRINTF(format, ...) xil_printf(format, ##__VA_ARGS__)
|
||||
//#define LPRINTF(format, ...)
|
||||
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
|
||||
|
||||
struct mem_file {
|
||||
const void *base;
|
||||
};
|
||||
|
||||
int mem_image_open(void *store, const char *path, const void **image_data)
|
||||
{
|
||||
struct mem_file *image = store;
|
||||
const void *fw_base = image->base;
|
||||
|
||||
(void)(path);
|
||||
if (image_data == NULL) {
|
||||
LPERROR("%s: input image_data is NULL\r\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
*image_data = fw_base;
|
||||
/* return an abitrary length, as the whole firmware is in memory */
|
||||
return 0x100;
|
||||
}
|
||||
|
||||
void mem_image_close(void *store)
|
||||
{
|
||||
/* The image is in memory, does nothing */
|
||||
(void)store;
|
||||
}
|
||||
|
||||
int mem_image_load(void *store, size_t offset, size_t size,
|
||||
const void **data, metal_phys_addr_t pa,
|
||||
struct metal_io_region *io,
|
||||
char is_blocking)
|
||||
{
|
||||
struct mem_file *image = store;
|
||||
const void *fw_base = image->base;
|
||||
|
||||
(void)is_blocking;
|
||||
|
||||
LPRINTF("%s: offset=0x%x, size=0x%x\n\r",
|
||||
__func__, offset, size);
|
||||
if (pa == METAL_BAD_PHYS) {
|
||||
if (data == NULL) {
|
||||
LPERROR("%s: data is NULL while pa is ANY\r\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
*data = (const void *)((const char *)fw_base + offset);
|
||||
} else {
|
||||
void *va;
|
||||
|
||||
if (io == NULL) {
|
||||
LPERROR("%s, io is NULL while pa is not ANY\r\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
va = metal_io_phys_to_virt(io, pa);
|
||||
if (va == NULL) {
|
||||
LPERROR("%s: no va is found\r\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(va, (const void *)((const char *)fw_base + offset), size);
|
||||
}
|
||||
|
||||
return (int)size;
|
||||
}
|
||||
|
||||
struct image_store_ops mem_image_store_ops = {
|
||||
.open = mem_image_open,
|
||||
.close = mem_image_close,
|
||||
.load = mem_image_load,
|
||||
.features = SUPPORT_SEEK,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* ZynqMP RPU life cycle management remoteproc example implementation
|
||||
*
|
||||
* Copyright(c) 2018 Xilinx Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <metal/alloc.h>
|
||||
#include <metal/sys.h>
|
||||
#include <metal/utilities.h>
|
||||
#include <openamp/remoteproc.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
/* Xilinx headers */
|
||||
#include <pm_api_sys.h>
|
||||
#include <pm_defs.h>
|
||||
#include <xil_mpu.h>
|
||||
#include <xil_printf.h>
|
||||
#include <xreg_cortexr5.h>
|
||||
|
||||
#define LPRINTF(format, ...) xil_printf(format, ##__VA_ARGS__)
|
||||
//#define LPRINTF(format, ...)
|
||||
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
|
||||
|
||||
#define RPU_BASE_ADDR 0xFF9A0000
|
||||
#define RPU_GLBL_CNTL_OFFSET 0
|
||||
#define RPU0_CFG_BASE_OFFSET 0x100
|
||||
#define RPU1_CFG_BASE_OFFSET 0x200
|
||||
#define RPU_CFG_BASE_OFFSET(n) (RPU0_CFG_BASE_OFFSET << (n))
|
||||
/* Boot memory bit. high for OCM, low for TCM */
|
||||
#define VINITHI_BIT metal_bit(2)
|
||||
/* CPU halt bit, high: processor is running. low: processor is halt */
|
||||
#define nCPUHALT_BIT metal_bit(0)
|
||||
/* RPU mode, high: split mode. low: lock step mode */
|
||||
#define SLSPLIT_BIT metal_bit(3)
|
||||
/* Clamp mode. high: split mode. low: lock step mode */
|
||||
#define SLCLAMP_BIT metal_bit(4)
|
||||
/* TCM mode. high: combine RPU TCMs. low: split TCM for RPU1 and RPU0 */
|
||||
#define TCM_COMB_BIT metal_bit(6)
|
||||
|
||||
struct r5_rproc_priv {
|
||||
struct remoteproc *rproc;
|
||||
int cpu_id;
|
||||
metal_phys_addr_t rpu_base;
|
||||
struct metal_io_region rpu_io;
|
||||
};
|
||||
|
||||
/**
|
||||
* r5_rproc_boot_addr_config - configure the boot address of R5
|
||||
* @pdata: platform data
|
||||
*
|
||||
* This function will set the boot address based on if the
|
||||
* boot memory in the ELF file is TCM or OCM
|
||||
*/
|
||||
static uint32_t r5_rproc_boot_addr_config(struct r5_rproc_priv *priv,
|
||||
metal_phys_addr_t bootaddr)
|
||||
{
|
||||
uint32_t rpu_resetaddr;
|
||||
|
||||
LPRINTF("%s: R5 ID: %d, boot_addr 0x%x\n",
|
||||
__func__, priv->cpu_id, bootaddr);
|
||||
|
||||
if (bootaddr < 0x40000)
|
||||
rpu_resetaddr = 0;
|
||||
else
|
||||
rpu_resetaddr = 1;
|
||||
return rpu_resetaddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* r5_rproc_mode_config - configure R5 operation mode
|
||||
* @pdata: platform data
|
||||
*
|
||||
* configure R5 to split mode or lockstep mode
|
||||
* based on the platform data.
|
||||
*/
|
||||
static void r5_rproc_mode_config(struct r5_rproc_priv *priv)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
LPRINTF("%s: mode: %d\n", __func__, priv->cpu_id);
|
||||
tmp = metal_io_read32(&priv->rpu_io, RPU_GLBL_CNTL_OFFSET);
|
||||
if (priv->cpu_id == NODE_RPU) {
|
||||
/* RPU lock step mode */
|
||||
tmp &= ~SLSPLIT_BIT;
|
||||
tmp |= TCM_COMB_BIT;
|
||||
tmp |= SLCLAMP_BIT;
|
||||
} else {
|
||||
/* RPU split mode */
|
||||
tmp |= SLSPLIT_BIT;
|
||||
tmp &= ~TCM_COMB_BIT;
|
||||
tmp &= ~SLCLAMP_BIT;
|
||||
}
|
||||
metal_io_write32(&priv->rpu_io, RPU_GLBL_CNTL_OFFSET, tmp);
|
||||
}
|
||||
|
||||
struct remoteproc *r5_rproc_init(struct remoteproc *rproc,
|
||||
struct remoteproc_ops *ops, void *arg)
|
||||
{
|
||||
struct r5_rproc_priv *priv;
|
||||
unsigned int cpu_id = *((unsigned int *)arg);
|
||||
|
||||
if (cpu_id < NODE_RPU_0 || cpu_id > NODE_RPU_1) {
|
||||
xil_printf("rproc init: invalide node id: %d\n\r", cpu_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xil_printf("rproc init: node id: %d\n\r", cpu_id);
|
||||
priv = metal_allocate_memory(sizeof(*priv));
|
||||
if (!priv)
|
||||
return NULL;
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
priv->rproc = rproc;
|
||||
priv->cpu_id = cpu_id;
|
||||
priv->rproc->ops = ops;
|
||||
metal_list_init(&priv->rproc->mems);
|
||||
priv->rproc->priv = priv;
|
||||
priv->rpu_base = RPU_BASE_ADDR;
|
||||
metal_io_init(&priv->rpu_io, (void *)RPU_BASE_ADDR, &priv->rpu_base,
|
||||
0x1000, (metal_phys_addr_t)(-1),
|
||||
DEVICE_NONSHARED | PRIV_RW_USER_RW, NULL);
|
||||
|
||||
r5_rproc_mode_config(priv);
|
||||
rproc->state = RPROC_READY;
|
||||
return priv->rproc;
|
||||
}
|
||||
|
||||
void r5_rproc_remove(struct remoteproc *rproc)
|
||||
{
|
||||
if (rproc) {
|
||||
struct r5_rproc_priv *priv;
|
||||
|
||||
priv = (struct r5_rproc_priv *)rproc->priv;
|
||||
metal_free_memory(priv);
|
||||
}
|
||||
}
|
||||
|
||||
void *r5_rproc_mmap(struct remoteproc *rproc,
|
||||
metal_phys_addr_t *pa, metal_phys_addr_t *da,
|
||||
size_t size, unsigned int attribute,
|
||||
struct metal_io_region **io)
|
||||
{
|
||||
struct remoteproc_mem *mem;
|
||||
struct r5_rproc_priv *priv;
|
||||
metal_phys_addr_t lpa, lda;
|
||||
|
||||
priv = rproc->priv;
|
||||
|
||||
if (!da || !pa)
|
||||
return NULL;
|
||||
LPRINTF("%s: pa=0x%x, da=0x%x, size=0x%x, atrribute=0x%x\n\r",
|
||||
__func__, *pa, *da, size, attribute);
|
||||
lda = *da;
|
||||
lpa = *pa;
|
||||
if (!attribute)
|
||||
attribute = NORM_SHARED_NCACHE | PRIV_RW_USER_RW;
|
||||
if (lda <= 0x40000) {
|
||||
metal_phys_addr_t lda_end;
|
||||
|
||||
lda_end = lda + size;
|
||||
if (priv->cpu_id == NODE_RPU_0 || priv->cpu_id == NODE_RPU) {
|
||||
lpa = 0xFFE00000 + lda;
|
||||
if (lda < 0x10000)
|
||||
XPm_RequestNode(NODE_TCM_0_A,
|
||||
PM_CAP_ACCESS, 0,
|
||||
REQUEST_ACK_BLOCKING);
|
||||
if (lda <= 0x20000 && lda_end >= 0x10000)
|
||||
XPm_RequestNode(NODE_TCM_1_A,
|
||||
PM_CAP_ACCESS, 0,
|
||||
REQUEST_ACK_BLOCKING);
|
||||
if (lda <= 0x30000 && lda_end >= 0x20000)
|
||||
XPm_RequestNode(NODE_TCM_0_B,
|
||||
PM_CAP_ACCESS, 0,
|
||||
REQUEST_ACK_BLOCKING);
|
||||
if (lda <= 0x40000 && lda_end >= 0x30000)
|
||||
XPm_RequestNode(NODE_TCM_1_B,
|
||||
PM_CAP_ACCESS, 0,
|
||||
REQUEST_ACK_BLOCKING);
|
||||
} else if (priv->cpu_id == NODE_RPU_1) {
|
||||
lpa = 0xFFE90000 + lda;
|
||||
if (lda < 0x10000)
|
||||
XPm_RequestNode(NODE_TCM_1_A,
|
||||
PM_CAP_ACCESS, 0,
|
||||
REQUEST_ACK_BLOCKING);
|
||||
if (lda <= 0x30000 && lda_end >= 0x20000)
|
||||
XPm_RequestNode(NODE_TCM_1_B,
|
||||
PM_CAP_ACCESS, 0,
|
||||
REQUEST_ACK_BLOCKING);
|
||||
} else {
|
||||
LPERROR("mmap failed: invalid cpu node: %d\n",
|
||||
priv->cpu_id);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (lpa == METAL_BAD_PHYS)
|
||||
lpa = lda;
|
||||
if (lpa == METAL_BAD_PHYS)
|
||||
return NULL;
|
||||
mem = metal_allocate_memory(sizeof(*mem));
|
||||
if (!mem)
|
||||
return NULL;
|
||||
mem->pa = lpa;
|
||||
mem->da = lda;
|
||||
|
||||
*io = metal_allocate_memory(sizeof(struct metal_io_region));
|
||||
if (!*io) {
|
||||
metal_free_memory(mem);
|
||||
return NULL;
|
||||
}
|
||||
metal_io_init(*io, (void *)mem->pa, &mem->pa, size,
|
||||
sizeof(metal_phys_addr_t)<<3, attribute, NULL);
|
||||
mem->io = *io;
|
||||
metal_list_add_tail(&rproc->mems, &mem->node);
|
||||
*pa = lpa;
|
||||
*da = lda;
|
||||
mem->size = size;
|
||||
return metal_io_phys_to_virt(*io, mem->pa);
|
||||
}
|
||||
|
||||
int r5_rproc_start(struct remoteproc *rproc)
|
||||
{
|
||||
struct r5_rproc_priv *priv;
|
||||
int ret;
|
||||
uint32_t resetaddr;
|
||||
|
||||
priv = rproc->priv;
|
||||
resetaddr = r5_rproc_boot_addr_config(priv, rproc->bootaddr);
|
||||
ret = XPm_RequestWakeUp(priv->cpu_id, true, resetaddr,
|
||||
REQUEST_ACK_BLOCKING);
|
||||
if (ret != XST_SUCCESS) {
|
||||
LPRINTF("%s: Failed to start RPU 0x%x, ret=0x%x\n\r",
|
||||
__func__, priv->cpu_id, ret);
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int r5_rproc_stop(struct remoteproc *rproc)
|
||||
{
|
||||
/* It is lacking a stop operation in the libPM */
|
||||
(void)rproc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int r5_rproc_shutdown(struct remoteproc *rproc)
|
||||
{
|
||||
struct r5_rproc_priv *priv;
|
||||
int ret;
|
||||
struct remoteproc_mem *mem;
|
||||
struct metal_list *node;
|
||||
|
||||
priv = rproc->priv;
|
||||
/* Delete all the registered remoteproc memories */
|
||||
metal_list_for_each(&rproc->mems, node) {
|
||||
struct metal_list *tmpnode;
|
||||
metal_phys_addr_t pa, pa_end;
|
||||
|
||||
mem = metal_container_of(node, struct remoteproc_mem, node);
|
||||
tmpnode = node;
|
||||
/* Release TCM resource */
|
||||
pa = mem->pa;
|
||||
pa_end = metal_io_phys(mem->io, metal_io_region_size(mem->io));
|
||||
if (priv->cpu_id == NODE_RPU_0 || priv->cpu_id == NODE_RPU) {
|
||||
if (pa < 0xFFE10000)
|
||||
XPm_RequestNode(NODE_TCM_0_A,
|
||||
PM_CAP_ACCESS, 0,
|
||||
REQUEST_ACK_BLOCKING);
|
||||
if (pa <= 0xFFE20000 && pa_end >= 0xFFE10000)
|
||||
XPm_RequestNode(NODE_TCM_1_A,
|
||||
PM_CAP_ACCESS, 0,
|
||||
REQUEST_ACK_BLOCKING);
|
||||
if (pa <= 0xFFE30000 && pa_end >= 0xFFE20000)
|
||||
XPm_RequestNode(NODE_TCM_0_B,
|
||||
PM_CAP_ACCESS, 0,
|
||||
REQUEST_ACK_BLOCKING);
|
||||
if (pa <= 0xFFE40000 && pa_end >= 0xFFE30000)
|
||||
XPm_RequestNode(NODE_TCM_1_B,
|
||||
PM_CAP_ACCESS, 0,
|
||||
REQUEST_ACK_BLOCKING);
|
||||
} else if (priv->cpu_id == NODE_RPU_1) {
|
||||
if (pa < 0xFFEA0000)
|
||||
XPm_RequestNode(NODE_TCM_1_A,
|
||||
PM_CAP_ACCESS, 0,
|
||||
REQUEST_ACK_BLOCKING);
|
||||
if (pa <= 0xFFC0000 && pa_end >= 0xFFEB0000)
|
||||
XPm_RequestNode(NODE_TCM_1_B,
|
||||
PM_CAP_ACCESS, 0,
|
||||
REQUEST_ACK_BLOCKING);
|
||||
}
|
||||
node = tmpnode->prev;
|
||||
metal_list_del(tmpnode);
|
||||
metal_free_memory(mem->io);
|
||||
metal_free_memory(mem);
|
||||
}
|
||||
|
||||
ret = XPm_ForcePowerDown(priv->cpu_id, REQUEST_ACK_BLOCKING);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct remoteproc_ops r5_rproc_ops = {
|
||||
.init = r5_rproc_init,
|
||||
.remove = r5_rproc_remove,
|
||||
.start = r5_rproc_start,
|
||||
.stop = r5_rproc_stop,
|
||||
.shutdown = r5_rproc_shutdown,
|
||||
.mmap = r5_rproc_mmap,
|
||||
};
|
||||
Reference in New Issue
Block a user