建立工程,成功创建两个虚拟串口

This commit is contained in:
ranchuan
2023-06-21 18:00:56 +08:00
commit 3604192d8f
872 changed files with 428764 additions and 0 deletions

View 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)

View 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 = &image;
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;
}

View 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 = .;
}

View File

@@ -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,
};

View File

@@ -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,
};