diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index c4f3b2a98..95b48e0f0 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -3,6 +3,7 @@ collector_create (APP_LIB_DIRS "") collector_create (APP_INC_DIRS "") collector_create (APP_LIB_DEPS "") +collector_create (APP_EXTRA_C_FLAGS "") set (APPS_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set (APPS_SHARE_DIR "${CMAKE_CURRENT_BINARY_DIR}/share") diff --git a/apps/examples/load_fw/CMakeLists.txt b/apps/examples/load_fw/CMakeLists.txt index 3f058e272..041126eff 100644 --- a/apps/examples/load_fw/CMakeLists.txt +++ b/apps/examples/load_fw/CMakeLists.txt @@ -1,5 +1,5 @@ - -set (_cflags "${CMAKE_C_FLAGS} ${APP_EXTRA_C_FLAGS}") +collector_list (_app_extra_c_flags APP_EXTRA_C_FLAGS) +set (_cflags "${CMAKE_C_FLAGS} ${_app_extra_c_flags}") set (_fw_dir "${APPS_SHARE_DIR}") collector_list (_list PROJECT_INC_DIRS) @@ -11,21 +11,24 @@ collector_list (_app_list APP_LIB_DIRS) link_directories (${_list} ${_app_list}) get_property (_linker_opt GLOBAL PROPERTY APP_LINKER_OPT) +collect (PROJECT_LIB_DEPS xilpm) 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") + list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/zynqmp_apu_lcm_rproc_example.c") + list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/zynqmp_rpu_lcm_rproc_example.c") + list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/platform_info.c") + list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/${_app}.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) + 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 ${_deps} -Wl,--end-group) install (TARGETS ${_app}.out RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif (WITH_STATIC_LIB) diff --git a/apps/examples/load_fw/common.h b/apps/examples/load_fw/common.h new file mode 100644 index 000000000..e4ed37355 --- /dev/null +++ b/apps/examples/load_fw/common.h @@ -0,0 +1,109 @@ +/* + * Copyright(c) 2019 Xilinx Ltd. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef COMMON_H_ +#define COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +/* Xilinx headers */ +#include +#include +#include +#include + +#ifdef versal +#include +#include + +#ifndef NODE_APU_0 +#define NODE_APU_0 PM_DEV_ACPU_0 +#endif +#ifndef NODE_APU_1 +#define NODE_APU_1 PM_DEV_ACPU_1 +#endif +#ifndef NODE_RPU_0 +#define NODE_RPU_0 PM_DEV_RPU0_0 +#endif +#ifndef NODE_RPU +#define NODE_RPU PM_DEV_RPU0_0 +#endif + +#ifndef NODE_RPU_1 +#define NODE_RPU_1 PM_DEV_RPU0_1 +#endif + +#ifndef NODE_TCM_0_A +#define NODE_TCM_0_A PM_DEV_TCM_0_A +#endif +#ifndef NODE_TCM_0_B +#define NODE_TCM_0_B PM_DEV_TCM_0_B +#endif +#ifndef NODE_TCM_1_A +#define NODE_TCM_1_A PM_DEV_TCM_1_A +#endif +#ifndef NODE_TCM_1_B +#define NODE_TCM_1_B PM_DEV_TCM_1_B +#endif + +#ifndef NODE_DDR +#define NODE_DDR PM_DEV_DDR_0 +#endif + +#ifndef NODE_OCM_BANK_0 +#define NODE_OCM_BANK_0 PM_DEV_OCM_0 +#endif +#ifndef NODE_OCM_BANK_1 +#define NODE_OCM_BANK_1 PM_DEV_OCM_1 +#endif +#ifndef NODE_OCM_BANK_2 +#define NODE_OCM_BANK_2 PM_DEV_OCM_2 +#endif +#ifndef NODE_OCM_BANK_3 +#define NODE_OCM_BANK_3 PM_DEV_OCM_3 +#endif + +/* Requirement limits */ +#define XPM_MAX_CAPABILITY (PM_CAP_ACCESS | PM_CAP_CONTEXT | PM_CAP_WAKEUP) +#define XPM_MAX_LATENCY (0xFFFFU) +#define XPM_MAX_QOS (100) +#define XPM_MIN_CAPABILITY (0) +#define XPM_MIN_LATENCY (0) +#define XPM_MIN_QOS (0) +#define XPM_DEF_CAPABILITY XPM_MAX_CAPABILITY +#define XPM_DEF_LATENCY XPM_MAX_LATENCY +#define XPM_DEF_QOS XPM_MAX_QOS + +enum XPmRequestAck { + REQUEST_ACK_NO = 1, + REQUEST_ACK_BLOCKING, + REQUEST_ACK_NON_BLOCKING, + REQUEST_ACK_CB_CERROR, +}; + +#else /* zynqmp */ +#include +#define XPM_MAX_QOS MAX_QOS +#define XPM_MIN_QOS (0) +#endif /* versal */ + +#define LPRINTF(format, ...) xil_printf(format, ##__VA_ARGS__) +//#define LPRINTF(format, ...) +#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__) + +struct rproc_priv { + struct remoteproc *rproc; + int cpu_id; +}; + +#endif /* COMMON_H_ */ diff --git a/apps/examples/load_fw/load_fw.c b/apps/examples/load_fw/load_fw.c index 19e267a9d..b0ed7f9e7 100644 --- a/apps/examples/load_fw/load_fw.c +++ b/apps/examples/load_fw/load_fw.c @@ -7,22 +7,9 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include -#include -#include -#include -#include -/* Xilinx headers */ -#include -#include -#include +#include +#include -#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 { @@ -33,57 +20,6 @@ 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\r\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\r\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) @@ -95,6 +31,7 @@ int load_exectuable_block(struct remoteproc *rproc, 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); @@ -109,6 +46,7 @@ int load_exectuable_block(struct remoteproc *rproc, return ret; } LPRINTF("successfully started the processor\r\n"); +#ifndef RPU_BOOT_LINUX /* ... */ asm volatile("wfi"); LPRINTF("going to stop the processor\r\n"); @@ -116,9 +54,11 @@ int load_exectuable_block(struct remoteproc *rproc, /* application may want to do some cleanup before shutdown */ LPRINTF("going to shutdown the processor\r\n"); remoteproc_shutdown(rproc); +#endif /* RPU_BOOT_LINUX */ return 0; } +#ifndef RPU_BOOT_LINUX int load_exectuable_noblock(struct remoteproc *rproc, struct image_store_ops *store_ops, void *store, const char *img_path) @@ -196,55 +136,38 @@ int load_exectuable_noblock(struct remoteproc *rproc, remoteproc_shutdown(rproc); return 0; } - +#endif /* RPU_BOOT_LINUX */ int main(void) { - struct remoteproc rproc; - struct remoteproc *ret_rproc; + struct remoteproc *rproc = NULL; void *store = ℑ - unsigned int cpu_id = NODE_RPU_1; + unsigned int cpu_id = LOAD_FW_TARGET; 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\r\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"); + LPRINTF("Loading Exectuable Demo\n"); + rproc = app_init(cpu_id); + if (!rproc) { + LPERROR("app_init failed\r\n"); return -1; } - - ret = load_exectuable_block(&rproc, &mem_image_store_ops, store, NULL); + 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); + remoteproc_shutdown(rproc); return -1; } - - ret = load_exectuable_noblock(&rproc, &mem_image_store_ops, store, +#ifndef RPU_BOOT_LINUX + 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); + remoteproc_shutdown(rproc); return -1; } - remoteproc_remove(&rproc); +#endif /* RPU_BOOT_LINUX */ + remoteproc_remove(rproc); return ret; } diff --git a/apps/examples/load_fw/mem_image_store.c b/apps/examples/load_fw/mem_image_store.c index f78ebf0cb..23dbd6486 100644 --- a/apps/examples/load_fw/mem_image_store.c +++ b/apps/examples/load_fw/mem_image_store.c @@ -7,19 +7,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include -#include -#include -#include -/* Xilinx headers */ -#include -#include -#include - -#define LPRINTF(format, ...) xil_printf(format, ##__VA_ARGS__) -//#define LPRINTF(format, ...) -#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__) +#include struct mem_file { const void *base; @@ -56,7 +44,7 @@ int mem_image_load(void *store, size_t offset, size_t size, (void)is_blocking; - LPRINTF("%s: offset=0x%x, size=0x%x\r\n", + LPRINTF("%s: offset=0x%x, size=0x%x\n\r", __func__, offset, size); if (pa == METAL_BAD_PHYS) { if (data == NULL) { diff --git a/apps/examples/load_fw/platform_info.c b/apps/examples/load_fw/platform_info.c new file mode 100644 index 000000000..9e6f6d1ba --- /dev/null +++ b/apps/examples/load_fw/platform_info.c @@ -0,0 +1,103 @@ +/* + * Copyright(c) 2019 Xilinx Ltd. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +extern struct remoteproc_ops zynqmp_apu_rproc_ops; +extern struct remoteproc_ops zynqmp_rpu_rproc_ops; + +static struct remoteproc rproc_inst; +static struct remoteproc_ops ops; + +static struct remoteproc * platform_create_proc(unsigned int cpu_id) +{ + struct remoteproc * rproc; + if (NODE_RPU_0 <= LOAD_FW_TARGET && LOAD_FW_TARGET <= NODE_RPU_1) + ops = zynqmp_rpu_rproc_ops; + else if (NODE_APU_0 <= LOAD_FW_TARGET && LOAD_FW_TARGET <= NODE_APU_1) + ops = zynqmp_apu_rproc_ops; + else + return NULL; + + rproc = remoteproc_init(&rproc_inst, &ops, &cpu_id); + if (!rproc) + return NULL; + return &rproc_inst; +} + +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); +} + +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; +} + +struct remoteproc * app_init(unsigned int cpu_id){ + struct metal_init_params metal_param = { + .log_handler = app_log_handler, + .log_level = METAL_LOG_DEBUG, + }; + metal_init(&metal_param); + + if (XST_SUCCESS != IpiConfigure(&IpiInst)) { + LPERROR("Failed to config IPI instance\r\n"); + return NULL; + } + + if (XST_SUCCESS != XPm_InitXilpm(&IpiInst)) { + LPERROR("Failed to initialize PM\r\n"); + return NULL; + } + + + return platform_create_proc(cpu_id); +} diff --git a/apps/examples/load_fw/platform_info.h b/apps/examples/load_fw/platform_info.h new file mode 100644 index 000000000..bcf644185 --- /dev/null +++ b/apps/examples/load_fw/platform_info.h @@ -0,0 +1,11 @@ +/* + * Copyright(c) 2019 Xilinx Ltd. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef PLATFORM_INFO_H_ +#define PLATFORM_INFO_H_ + +struct remoteproc * app_init(unsigned int cpu_id); +#endif /* PLATFORM_INFO_H_ */ diff --git a/apps/examples/load_fw/zynqmp_apu_lcm_rproc_example.c b/apps/examples/load_fw/zynqmp_apu_lcm_rproc_example.c new file mode 100644 index 000000000..2caec2734 --- /dev/null +++ b/apps/examples/load_fw/zynqmp_apu_lcm_rproc_example.c @@ -0,0 +1,176 @@ +/* + * ZynqMP APU life cycle management remoteproc example implementation + * + * Copyright(c) 2019 Xilinx Ltd. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +static struct remoteproc *apu_rproc_init(struct remoteproc *rproc, + struct remoteproc_ops *ops, void *arg) +{ + struct rproc_priv *priv; + unsigned int cpu_id = *((unsigned int *)arg); + if(cpu_id < NODE_APU_0 || cpu_id > NODE_APU_1) { + LPERROR("%s: invalid node id: %d \n\r",__func__, cpu_id); + return NULL; + } + + LPRINTF("%s: node id: %d\n\r", __func__, 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; + rproc->state = RPROC_READY; + return priv->rproc; +} + +static void apu_rproc_remove(struct remoteproc *rproc) +{ + struct rproc_priv *priv; + + priv = (struct rproc_priv *)rproc->priv; + metal_free_memory(priv); +} + +static void *apu_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; + metal_phys_addr_t lpa, lda, lda_end; + + if ((!da || !pa) || (*da == METAL_BAD_PHYS && *pa == METAL_BAD_PHYS)) + 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; + + + lda_end = lda + size; + if (lda_end <= 0x80000000) + XPm_RequestNode(NODE_DDR,PM_CAP_ACCESS, + XPM_MIN_QOS,REQUEST_ACK_NO); + if (lda >= 0xFFFC0000 && lda < 0xFFFD0000) + XPm_RequestNode(NODE_OCM_BANK_0,PM_CAP_ACCESS, + XPM_MIN_QOS,REQUEST_ACK_NO); + if (lda <= 0xFFFDFFFF && lda_end >= 0xFFFD0000) + XPm_RequestNode(NODE_OCM_BANK_1,PM_CAP_ACCESS, + XPM_MIN_QOS,REQUEST_ACK_NO); + if (lda <= 0xFFFEFFFF && lda_end >= 0xFFFE0000) + XPm_RequestNode(NODE_OCM_BANK_2,PM_CAP_ACCESS, + XPM_MIN_QOS,REQUEST_ACK_NO); + if (lda_end >= 0xFFFF0000) + XPm_RequestNode(NODE_OCM_BANK_3,PM_CAP_ACCESS, + XPM_MIN_QOS,REQUEST_ACK_NO); + + 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; + } + + /* This code only runs on the R5, which has a flat memory + * space. Therefore, we use the same value for the physical + * and virtual addresses we pass in to metal_io_init(). + */ + 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); +} + +static int apu_rproc_start(struct remoteproc *rproc) +{ + struct rproc_priv *priv; + int ret; + + priv = rproc->priv; + ret = XPm_RequestWakeUp(priv->cpu_id, true,rproc->bootaddr, + REQUEST_ACK_NO); + if (ret != XST_SUCCESS) { + LPRINTF("%s: Failed to start APU 0x%x, ret=0x%x\n\r", + __func__, priv->cpu_id, ret); + return -1; + } + return 0; +} + +static int apu_rproc_stop(struct remoteproc *rproc) +{ + /* It is lacking a stop operation in the libPM */ + (void)rproc; + return 0; +} + +static int apu_rproc_shutdown(struct remoteproc *rproc) +{ + struct 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 (pa_end <= 0x7FFFFFFF) + XPm_ReleaseNode(NODE_DDR); + if (pa >= 0xFFFC0000 && pa < 0xFFFD0000) + XPm_ReleaseNode(NODE_OCM_BANK_0); + if (pa <= 0xFFFDFFFF && pa_end >= 0xFFFD0000) + XPm_ReleaseNode(NODE_OCM_BANK_1); + if (pa <= 0xFFFEFFFF && pa_end >= 0xFFFE0000) + XPm_ReleaseNode(NODE_OCM_BANK_2); + if (pa_end >= 0xFFFF0000) + XPm_ReleaseNode(NODE_OCM_BANK_3); + + node = tmpnode->prev; + metal_list_del(tmpnode); + metal_free_memory(mem->io); + metal_free_memory(mem); + } + ret = XPm_ForcePowerDown(priv->cpu_id, REQUEST_ACK_NO); + if (ret != XST_SUCCESS) + return -1; + return 0; +} + +struct remoteproc_ops zynqmp_apu_rproc_ops = { + .init = apu_rproc_init, + .remove = apu_rproc_remove, + .start = apu_rproc_start, + .stop = apu_rproc_stop, + .shutdown = apu_rproc_shutdown, + .mmap = apu_rproc_mmap, +}; diff --git a/apps/examples/load_fw/zynqmp_rpu_lcm_rproc_example.c b/apps/examples/load_fw/zynqmp_rpu_lcm_rproc_example.c new file mode 100644 index 000000000..34f9b6b1e --- /dev/null +++ b/apps/examples/load_fw/zynqmp_rpu_lcm_rproc_example.c @@ -0,0 +1,203 @@ +/* + * ZynqMP RPU life cycle management remoteproc example implementation + * + * Copyright(c) 2019 Xilinx Ltd. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include + +static struct remoteproc *rpu_rproc_init(struct remoteproc *rproc, + struct remoteproc_ops *ops, void *arg) +{ + struct rproc_priv *priv; + unsigned int cpu_id = *((unsigned int *)arg); + + if (cpu_id < NODE_RPU_0 || cpu_id > NODE_RPU_1) { + LPERROR("%s: invalid node id: %d\n\r", __func__, cpu_id); + return NULL; + } + + LPRINTF("%s: node id: %d\n\r", __func__, 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; + rproc->state = RPROC_READY; + return priv->rproc; +} + +static void rpu_rproc_remove(struct remoteproc *rproc) +{ + struct rproc_priv *priv; + + priv = (struct rproc_priv *)rproc->priv; + metal_free_memory(priv); +} + +static void *rpu_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 rproc_priv *priv; + metal_phys_addr_t lpa, lda, lda_end; + + priv = rproc->priv; + + if ((!da || !pa) || (*da == METAL_BAD_PHYS && *pa == METAL_BAD_PHYS)) + 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; + + lda_end = lda + size; + /* call xilpm request node for relevant memory */ + if (lda <= 0x40000) { + 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, + XPM_MIN_QOS,REQUEST_ACK_NO); + if (lda <= 0x20000 && lda_end >= 0x10000) + XPm_RequestNode(NODE_TCM_1_A,PM_CAP_ACCESS, + XPM_MIN_QOS,REQUEST_ACK_NO); + if (lda <= 0x30000 && lda_end >= 0x20000) + XPm_RequestNode(NODE_TCM_0_B,PM_CAP_ACCESS, + XPM_MIN_QOS,REQUEST_ACK_NO); + if (lda <= 0x40000 && lda_end >= 0x30000) + XPm_RequestNode(NODE_TCM_1_B,PM_CAP_ACCESS, + XPM_MIN_QOS,REQUEST_ACK_NO); + } else if (priv->cpu_id == NODE_RPU_1) { + lpa = 0xFFE90000 + lda; + if (lda < 0x10000) + XPm_RequestNode(NODE_TCM_1_A,PM_CAP_ACCESS, + XPM_MIN_QOS,REQUEST_ACK_NO); + if (lda <= 0x30000 && lda_end >= 0x20000) + XPm_RequestNode(NODE_TCM_1_B,PM_CAP_ACCESS, + XPM_MIN_QOS,REQUEST_ACK_NO); + } else { + LPERROR("mmap failed: invalid cpu node: %d\r\n", priv->cpu_id); + 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; + } + + /* This code only runs on the R5, which has a flat memory + * space. Therefore, we use the same value for the physical + * and virtual addresses we pass in to metal_io_init(). + */ + 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); +} + +static int rpu_rproc_start(struct remoteproc *rproc) +{ + struct rproc_priv *priv; + int ret; + + priv = rproc->priv; + ret = XPm_RequestWakeUp(priv->cpu_id, true, rproc->bootaddr, + REQUEST_ACK_NO); + if (ret != XST_SUCCESS) { + LPRINTF("%s: Failed to start RPU 0x%x, ret=0x%x\n\r", + __func__, priv->cpu_id, ret); + return -1; + } + return 0; +} + +static int rpu_rproc_stop(struct remoteproc *rproc) +{ + /* It is lacking a stop operation in the libPM */ + (void)rproc; + return 0; +} + +static int rpu_rproc_shutdown(struct remoteproc *rproc) +{ + struct 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)); + node = tmpnode->prev; + metal_list_del(tmpnode); + metal_free_memory(mem->io); + metal_free_memory(mem); + /* call xilpm release node for relevant memory */ + if (pa <= 0x40000) { + if (priv->cpu_id == NODE_RPU_0 || priv->cpu_id == NODE_RPU) { + if (pa < 0x10000) + XPm_ReleaseNode(NODE_TCM_0_A); + if (pa <= 0x20000 && pa_end >= 0x10000) + XPm_ReleaseNode(NODE_TCM_1_A); + if (pa <= 0x30000 && pa_end >= 0x20000) + XPm_ReleaseNode(NODE_TCM_0_B); + if (pa <= 0x40000 && pa_end >= 0x30000) + XPm_ReleaseNode(NODE_TCM_1_B); + } else if (priv->cpu_id == NODE_RPU_1) { + if (pa < 0x10000) + XPm_ReleaseNode(NODE_TCM_1_A); + if (pa <= 0x30000 && pa_end >= 0x20000) + XPm_ReleaseNode(NODE_TCM_1_B); + } else { + LPERROR("unmap failed: invalid cpu node: %d\r\n", priv->cpu_id); + return NULL; + } + } + + } + + ret = XPm_ForcePowerDown(priv->cpu_id, REQUEST_ACK_NO); + if (ret != XST_SUCCESS) + return -1; + return 0; +} + +struct remoteproc_ops zynqmp_rpu_rproc_ops = { + .init = rpu_rproc_init, + .remove = rpu_rproc_remove, + .start = rpu_rproc_start, + .stop = rpu_rproc_stop, + .shutdown = rpu_rproc_shutdown, + .mmap = rpu_rproc_mmap, +}; diff --git a/apps/machine/zynqmp/CMakeLists.txt b/apps/machine/zynqmp/CMakeLists.txt index 57df64414..f948380a3 100644 --- a/apps/machine/zynqmp/CMakeLists.txt +++ b/apps/machine/zynqmp/CMakeLists.txt @@ -1,4 +1,3 @@ collect (APP_COMMON_SOURCES platform_info.c) collect (APP_COMMON_SOURCES zynqmp_linux_r5_proc.c) collect (APP_INC_DIRS "${CMAKE_CURRENT_SOURCE_DIR}") - diff --git a/apps/machine/zynqmp/platform_info.c b/apps/machine/zynqmp/platform_info.c index 8ac2d1074..3081ec96b 100644 --- a/apps/machine/zynqmp/platform_info.c +++ b/apps/machine/zynqmp/platform_info.c @@ -34,23 +34,28 @@ #define RPU_CPU_ID 0 /* RPU remote CPU Index. We only talk to * one CPU in the exmaple. We set the CPU * index to 0. */ -#define IPI_CHN_BITMASK 0x00000100 /* IPI channel bit mask for IPI +#ifdef versal +#define IPI_CHN_BITMASK 0x08 /* IPI channel bit mask for IPI * from/to RPU0 */ +#define IPI_DEV_NAME "ff360000.ipi" /* IPI device name */ +#else +#define IPI_CHN_BITMASK 0x00000100 +#define IPI_DEV_NAME "ff340000.ipi" +#endif /* versal */ #define DEV_BUS_NAME "platform" /* device bus name. "platform" bus * is used in Linux kernel for generic * devices */ /* libmetal devices names used in the examples. * They are platform devices, you find them in Linux sysfs * sys/bus/platform/devices */ -#define IPI_DEV_NAME "ff340000.ipi" /* IPI device name */ #define SHM_DEV_NAME "3ed20000.shm" /* shared device name */ -#define RSC_MEM_PA 0x3ED20000UL -#define RSC_MEM_SIZE 0x2000UL -#define VRING_MEM_PA 0x3ED40000UL -#define VRING_MEM_SIZE 0x8000UL -#define SHARED_BUF_PA 0x3ED48000UL -#define SHARED_BUF_SIZE 0x40000UL +#define RSC_MEM_PA 0x3ED20000UL +#define RSC_MEM_SIZE 0x2000UL +#define VRING_MEM_PA 0x3ED40000UL +#define VRING_MEM_SIZE 0x8000UL +#define SHARED_BUF_PA 0x3ED48000UL +#define SHARED_BUF_SIZE 0x40000UL struct remoteproc_priv rproc_priv = { .ipi_name = IPI_DEV_NAME, diff --git a/apps/machine/zynqmp_r5/platform_info.c b/apps/machine/zynqmp_r5/platform_info.c index 091c39886..96c03c92f 100644 --- a/apps/machine/zynqmp_r5/platform_info.c +++ b/apps/machine/zynqmp_r5/platform_info.c @@ -29,9 +29,6 @@ #define IPI_DEV_NAME "ipi_dev" #define IPI_BUS_NAME "generic" -#define IPI_BASE_ADDR XPAR_XIPIPSU_0_BASE_ADDRESS /* IPI base address*/ -#define IPI_CHN_BITMASK 0x01000000 /* IPI channel bit mask for IPI from/to - APU */ /* Cortex R5 memory attributes */ #define DEVICE_SHARED 0x00000001U /* device, shareable */ diff --git a/apps/machine/zynqmp_r5/platform_info.h b/apps/machine/zynqmp_r5/platform_info.h index c13afdf73..718bb409f 100644 --- a/apps/machine/zynqmp_r5/platform_info.h +++ b/apps/machine/zynqmp_r5/platform_info.h @@ -17,7 +17,16 @@ extern "C" { #define PRIV_RW_USER_RW (0x00000003U<<8U) /* Full Access */ /* Interrupt vectors */ -#define IPI_IRQ_VECT_ID XPAR_XIPIPSU_0_INT_ID +#ifdef versal +#define IPI_IRQ_VECT_ID 63 +#define IPI_BASE_ADDR 0xFF340000 /* IPI base address*/ +#define IPI_CHN_BITMASK 0x0000020 /* IPI channel bit mask for IPI from/to + APU */ +#else +#define IPI_IRQ_VECT_ID XPAR_XIPIPSU_0_INT_ID +#define IPI_BASE_ADDR XPAR_XIPIPSU_0_BASE_ADDRESS +#define IPI_CHN_BITMASK 0x01000000 +#endif /* versal */ struct remoteproc_priv { const char *ipi_name; /**< IPI device name */ diff --git a/apps/system/generic/machine/zynqmp_r5/CMakeLists.txt b/apps/system/generic/machine/zynqmp_r5/CMakeLists.txt index e6e26e41b..d5d4e10da 100644 --- a/apps/system/generic/machine/zynqmp_r5/CMakeLists.txt +++ b/apps/system/generic/machine/zynqmp_r5/CMakeLists.txt @@ -1,3 +1,5 @@ +include(CheckSymbolExists) + collect (APP_COMMON_SOURCES helper.c) set (_linker_script "${CMAKE_CURRENT_SOURCE_DIR}/linker_remote.ld") @@ -12,6 +14,23 @@ find_library(LIBXIL_LIB NAMES xil PATHS ${CMAKE_FIND_ROOT_PATH}) get_filename_component(LIBXIL_LIB_DIR ${LIBXIL_LIB} DIRECTORY) collect(PROJECT_LIB_DIRS ${LIBXIL_LIB_DIR}) +# check PM API for certain headers and set client version based +CHECK_SYMBOL_EXISTS(XPAR_XILPM_ENABLED "xparameters.h" PM_FOUND) +if(PM_FOUND) + find_library(HAS_PM_LIB NAMES xilpm PATHS ${CMAKE_FIND_ROOT_PATH}) + collect (PROJECT_LIB_DEPS xilpm) + CHECK_SYMBOL_EXISTS(versal "xparameters.h" VERSION_2_PM_CLIENT) + if (VERSION_2_PM_CLIENT) + collect (APP_EXTRA_C_FLAGS " -DVERSION_2_PM_CLIENT ") + else() + collect (APP_EXTRA_C_FLAGS " -DVERSION_1_PM_CLIENT ") + endif(VERSION_2_PM_CLIENT) +endif(PM_FOUND) + collect(PROJECT_LIB_DEPS xil) collect(PROJECT_LIB_DEPS c) collect(PROJECT_LIB_DEPS m) +find_library(XILMEM_LIB NAMES xilmem PATHS ${CMAKE_FIND_ROOT_PATH}) +if(XILMEM_LIB) + collect (PROJECT_LIB_DEPS xilmem) +endif(XILMEM_LIB) diff --git a/apps/system/linux/machine/generic/platform_info.c b/apps/system/linux/machine/generic/platform_info.c index 0b0f72199..5743c5c3c 100644 --- a/apps/system/linux/machine/generic/platform_info.c +++ b/apps/system/linux/machine/generic/platform_info.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -58,20 +59,22 @@ struct remoteproc_priv { int shm_size; struct metal_io_region *shm_old_io; struct metal_io_region shm_new_io; + struct metal_generic_shmem *metal_shm; + struct metal_scatter_list *sg; struct remoteproc_mem shm; struct vring_ipi_info ipi; }; static struct remoteproc_priv rproc_priv_table [] = { { - .shm_file = "openamp.shm", + .shm_file = "linux_shm/openamp.shm", .shm_size = 0x80000, .ipi = { .path = "unixs:/tmp/openamp.event.0", }, }, { - .shm_file = "openamp.shm", + .shm_file = "linux_shm/openamp.shm", .shm_size = 0x80000, .ipi = { .path = "unix:/tmp/openamp.event.0", @@ -228,6 +231,8 @@ linux_proc_init(struct remoteproc *rproc, struct remoteproc_priv *prproc = arg; struct metal_io_region *io; struct remoteproc_mem *shm; + struct metal_generic_shmem *metal_shm = NULL; + struct metal_scatter_list *sg = NULL; struct vring_ipi_info *ipi; int ret; @@ -235,12 +240,20 @@ linux_proc_init(struct remoteproc *rproc, return NULL; rproc->priv = prproc; /* Create shared memory io */ - ret = metal_shmem_open(prproc->shm_file, prproc->shm_size, &io); + ret = metal_shmem_open(prproc->shm_file, prproc->shm_size, 0, &metal_shm); if (ret) { printf("Failed to init rproc, failed to open shm %s.\r\n", prproc->shm_file); return NULL; } + prproc->metal_shm = metal_shm; + sg = metal_shmem_mmap(metal_shm, prproc->shm_size); + if (sg == NULL) { + printf("Failed mmap shmem with libmetal.\n"); + goto err; + } + prproc->sg = sg; + io = sg->ios; prproc->shm_old_io = io; shm = &prproc->shm; shm->pa = 0; @@ -270,6 +283,12 @@ linux_proc_init(struct remoteproc *rproc, return rproc; err: + if (sg != NULL) { + metal_shmem_munmap(metal_shm, sg); + } + if (metal_shm != NULL) { + metal_shmem_close(metal_shm); + } return NULL; } @@ -278,7 +297,6 @@ static void linux_proc_remove(struct remoteproc *rproc) { struct remoteproc_priv *prproc; struct vring_ipi_info *ipi; - struct metal_io_region *io; if (!rproc) return; @@ -293,10 +311,11 @@ static void linux_proc_remove(struct remoteproc *rproc) } /* Close shared memory */ - io = prproc->shm_old_io; - if (io && io->ops.close) { - io->ops.close(io); - prproc->shm_old_io = NULL; + if (prproc->metal_shm) { + if (prproc->sg) { + metal_shmem_munmap(prproc->metal_shm, prproc->sg); + } + metal_shmem_close(prproc->metal_shm); } } @@ -371,19 +390,29 @@ static int platform_slave_setup_resource_table(const char *shm_file, metal_phys_addr_t rsc_pa) { struct metal_io_region *io; + struct metal_generic_shmem *metal_shm = NULL; + struct metal_scatter_list *sg = NULL; void *rsc_shm; int ret; - ret = metal_shmem_open(shm_file, shm_size, &io); + /* Get shared memory io */ + ret = metal_shmem_open(shm_file, shm_size, 0, &metal_shm); if (ret) { - printf("Failed to init rproc, failed to open shm %s.\r\n", + printf("Failed to setup rsc table, failed to open shm %s.\r\n", shm_file); return -1; } + sg = metal_shmem_mmap(metal_shm, shm_size); + if (sg == NULL) { + printf("Failed to setup rsc table, mmap with libmetal failed.\r\n"); + metal_shmem_close(metal_shm); + return -1; + } + io = sg->ios; rsc_shm = metal_io_virt(io, rsc_pa); memcpy(rsc_shm, rsc_table, rsc_size); - io->ops.close(io); - free(io); + metal_shmem_munmap(metal_shm, sg); + metal_shmem_close(metal_shm); return 0; } diff --git a/cmake/options.cmake b/cmake/options.cmake index 42762b124..93f6c4e76 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -43,6 +43,11 @@ if (WITH_APPS) endif (WITH_PROXY) endif (WITH_APPS) +# LOAD_FW only allowed for R5, otherwise turn off +if (NOT ${MACHINE} STREQUAL "zynqmp_r5") + set (WITH_LOAD_FW OFF) +endif(NOT ${MACHINE} STREQUAL "zynqmp_r5") + option (WITH_VIRTIO_MASTER "Build with virtio master enabled" ON) option (WITH_VIRTIO_SLAVE "Build with virtio slave enabled" ON)