zynqmp: pm: Implement IOCTL APIs for remoteproc
Implement ioctl APIs which uses MMIO operations
to control RPU operations. Below IOCTLs are supported
in this patch:
* Get RPU operation mode
* Set RPU operation mode
* Configure RPU boot address (OCM/TCM)
* Configure TCM combined mode
Signed-off-by: Rajan Vaja <rajanv@xilinx.com>
Signed-off-by: Jolly Shah <jollys@xilinx.com>
diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk
index cefb73a..2abcd28 100644
--- a/plat/xilinx/zynqmp/platform.mk
+++ b/plat/xilinx/zynqmp/platform.mk
@@ -78,6 +78,7 @@
plat/xilinx/zynqmp/pm_service/pm_svc_main.c \
plat/xilinx/zynqmp/pm_service/pm_api_sys.c \
plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c \
+ plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c \
plat/xilinx/zynqmp/pm_service/pm_ipi.c \
plat/xilinx/zynqmp/pm_service/pm_client.c \
plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
new file mode 100644
index 0000000..6f94f42
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for ioctl.
+ */
+
+#include <arch_helpers.h>
+#include <delay_timer.h>
+#include <mmio.h>
+#include <platform.h>
+#include "pm_api_ioctl.h"
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_common.h"
+#include "pm_ipi.h"
+#include "../zynqmp_def.h"
+
+/**
+ * pm_ioctl_get_rpu_oper_mode () - Get current RPU operation mode
+ * @mode Buffer to store value of oper mode(Split/Lock-step)
+ *
+ * This function provides current configured RPU operational mode.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_get_rpu_oper_mode(unsigned int *mode)
+{
+ unsigned int val;
+
+ val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
+ val &= ZYNQMP_SLSPLIT_MASK;
+ if (val)
+ *mode = PM_RPU_MODE_SPLIT;
+ else
+ *mode = PM_RPU_MODE_LOCKSTEP;
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ioctl_set_rpu_oper_mode () - Configure RPU operation mode
+ * @mode Value to set for oper mode(Split/Lock-step)
+ *
+ * This function configures RPU operational mode(Split/Lock-step).
+ * It also sets TCM combined mode in RPU lock-step and TCM non-combined
+ * mode for RPU split mode. In case of Lock step mode, RPU1's output is
+ * clamped.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_rpu_oper_mode(unsigned int mode)
+{
+ unsigned int val;
+
+ if (mmio_read_32(CRL_APB_RST_LPD_TOP) && CRL_APB_RPU_AMBA_RESET)
+ return PM_RET_ERROR_ACCESS;
+
+ val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
+
+ if (mode == PM_RPU_MODE_SPLIT) {
+ val |= ZYNQMP_SLSPLIT_MASK;
+ val &= ~ZYNQMP_TCM_COMB_MASK;
+ val &= ~ZYNQMP_SLCLAMP_MASK;
+ } else if (mode == PM_RPU_MODE_LOCKSTEP) {
+ val &= ~ZYNQMP_SLSPLIT_MASK;
+ val |= ZYNQMP_TCM_COMB_MASK;
+ val |= ZYNQMP_SLCLAMP_MASK;
+ } else {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ mmio_write_32(ZYNQMP_RPU_GLBL_CNTL, val);
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ioctl_config_boot_addr() - Configure RPU boot address
+ * @nid Node ID of RPU
+ * @value Value to set for boot address (TCM/OCM)
+ *
+ * This function configures RPU boot address(memory).
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_config_boot_addr(enum pm_node_id nid,
+ unsigned int value)
+{
+ unsigned int rpu_cfg_addr, val;
+
+ if (nid == NODE_RPU_0)
+ rpu_cfg_addr = ZYNQMP_RPU0_CFG;
+ else if (nid == NODE_RPU_1)
+ rpu_cfg_addr = ZYNQMP_RPU1_CFG;
+ else
+ return PM_RET_ERROR_ARGS;
+
+ val = mmio_read_32(rpu_cfg_addr);
+
+ if (value == PM_RPU_BOOTMEM_LOVEC)
+ val &= ~ZYNQMP_VINITHI_MASK;
+ else if (value == PM_RPU_BOOTMEM_HIVEC)
+ val |= ZYNQMP_VINITHI_MASK;
+ else
+ return PM_RET_ERROR_ARGS;
+
+ mmio_write_32(rpu_cfg_addr, val);
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ioctl_config_tcm_comb() - Configure TCM combined mode
+ * @value Value to set (Split/Combined)
+ *
+ * This function configures TCM to be in split mode or combined
+ * mode.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_config_tcm_comb(unsigned int value)
+{
+ unsigned int val;
+
+ val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
+
+ if (value == PM_RPU_TCM_SPLIT)
+ val &= ~ZYNQMP_TCM_COMB_MASK;
+ else if (value == PM_RPU_TCM_COMB)
+ val |= ZYNQMP_TCM_COMB_MASK;
+ else
+ return PM_RET_ERROR_ARGS;
+
+ mmio_write_32(ZYNQMP_RPU_GLBL_CNTL, val);
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_ioctl() - PM IOCTL API for device control and configs
+ * @node_id Node ID of the device
+ * @ioctl_id ID of the requested IOCTL
+ * @arg1 Argument 1 to requested IOCTL call
+ * @arg2 Argument 2 to requested IOCTL call
+ * @value Returned output value
+ *
+ * This function calls IOCTL to firmware for device control and configuration.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_ioctl(enum pm_node_id nid,
+ unsigned int ioctl_id,
+ unsigned int arg1,
+ unsigned int arg2,
+ unsigned int *value)
+{
+ int ret;
+
+ switch (ioctl_id) {
+ case IOCTL_GET_RPU_OPER_MODE:
+ ret = pm_ioctl_get_rpu_oper_mode(value);
+ break;
+ case IOCTL_SET_RPU_OPER_MODE:
+ ret = pm_ioctl_set_rpu_oper_mode(arg1);
+ break;
+ case IOCTL_RPU_BOOT_ADDR_CONFIG:
+ ret = pm_ioctl_config_boot_addr(nid, arg1);
+ break;
+ case IOCTL_TCM_COMB_CONFIG:
+ ret = pm_ioctl_config_tcm_comb(arg1);
+ break;
+ default:
+ ret = PM_RET_ERROR_NOTSUPPORTED;
+ }
+
+ return ret;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h
new file mode 100644
index 0000000..9dae69f
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for pin control.
+ */
+
+#ifndef _PM_API_IOCTL_H_
+#define _PM_API_IOCTL_H_
+
+#include "pm_common.h"
+
+enum pm_ioctl_id {
+ IOCTL_GET_RPU_OPER_MODE,
+ IOCTL_SET_RPU_OPER_MODE,
+ IOCTL_RPU_BOOT_ADDR_CONFIG,
+ IOCTL_TCM_COMB_CONFIG,
+};
+
+enum rpu_oper_mode {
+ PM_RPU_MODE_LOCKSTEP,
+ PM_RPU_MODE_SPLIT,
+};
+
+enum rpu_boot_mem {
+ PM_RPU_BOOTMEM_LOVEC,
+ PM_RPU_BOOTMEM_HIVEC,
+};
+
+enum rpu_tcm_comb {
+ PM_RPU_TCM_SPLIT,
+ PM_RPU_TCM_COMB,
+};
+
+enum pm_ret_status pm_api_ioctl(enum pm_node_id nid,
+ unsigned int ioctl_id,
+ unsigned int arg1,
+ unsigned int arg2,
+ unsigned int *value);
+#endif /* _PM_API_IOCTL_H_ */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
index 14c78fd..be24371 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
@@ -11,6 +11,7 @@
#include <arch_helpers.h>
#include <platform.h>
+#include "pm_api_ioctl.h"
#include "pm_api_pinctrl.h"
#include "pm_api_sys.h"
#include "pm_client.h"
@@ -636,3 +637,24 @@
{
return pm_api_pinctrl_set_config(pin, param, value);
}
+
+/**
+ * pm_ioctl() - PM IOCTL API for device control and configs
+ * @node_id Node ID of the device
+ * @ioctl_id ID of the requested IOCTL
+ * @arg1 Argument 1 to requested IOCTL call
+ * @arg2 Argument 2 to requested IOCTL call
+ * @out Returned output value
+ *
+ * This function calls IOCTL to firmware for device control and configuration.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_ioctl(enum pm_node_id nid,
+ unsigned int ioctl_id,
+ unsigned int arg1,
+ unsigned int arg2,
+ unsigned int *value)
+{
+ return pm_api_ioctl(nid, ioctl_id, arg1, arg2, value);
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
index f240d49..1c91e8f 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
@@ -105,5 +105,10 @@
enum pm_ret_status pm_pinctrl_set_config(unsigned int pin,
unsigned int param,
unsigned int value);
+enum pm_ret_status pm_ioctl(enum pm_node_id nid,
+ unsigned int ioctl_id,
+ unsigned int arg1,
+ unsigned int arg2,
+ unsigned int *value);
#endif /* _PM_API_SYS_H_ */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h
index c9656e3..afd92f6 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_defs.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h
@@ -75,6 +75,7 @@
PM_PINCTRL_SET_FUNCTION,
PM_PINCTRL_CONFIG_PARAM_GET,
PM_PINCTRL_CONFIG_PARAM_SET,
+ PM_IOCTL,
PM_API_MAX
};
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
index 22b6bc3..648de24 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
@@ -280,6 +280,15 @@
ret = pm_pinctrl_set_config(pm_arg[0], pm_arg[1], pm_arg[2]);
SMC_RET1(handle, (uint64_t)ret);
+ case PM_IOCTL:
+ {
+ uint32_t value;
+
+ ret = pm_ioctl(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+ }
+
default:
WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
SMC_RET1(handle, SMC_UNK);
diff --git a/plat/xilinx/zynqmp/zynqmp_def.h b/plat/xilinx/zynqmp/zynqmp_def.h
index 45fa387..54036f9 100644
--- a/plat/xilinx/zynqmp/zynqmp_def.h
+++ b/plat/xilinx/zynqmp/zynqmp_def.h
@@ -47,7 +47,9 @@
#define CRL_APB_RPLL_CTRL (CRL_APB_BASE + 0x30)
#define CRL_APB_BOOT_MODE_USER (CRL_APB_BASE + 0x200)
#define CRL_APB_RESET_CTRL (CRL_APB_BASE + 0x218)
+#define CRL_APB_RST_LPD_TOP (CRL_APB_BASE + 0x23C)
+#define CRL_APB_RPU_AMBA_RESET (1 << 2)
#define CRL_APB_RPLL_CTRL_BYPASS (1 << 3)
#define CRL_APB_RESET_CTRL_SOFT_RESET (1 << 4)
@@ -176,4 +178,12 @@
#define IOU_SLCR_BASEADDR 0xFF180000
+#define ZYNQMP_RPU_GLBL_CNTL 0xFF9A0000
+#define ZYNQMP_RPU0_CFG 0xFF9A0100
+#define ZYNQMP_RPU1_CFG 0xFF9A0200
+#define ZYNQMP_SLSPLIT_MASK 0x08
+#define ZYNQMP_TCM_COMB_MASK 0x40
+#define ZYNQMP_SLCLAMP_MASK 0x10
+#define ZYNQMP_VINITHI_MASK 0x04
+
#endif /* __ZYNQMP_DEF_H__ */