xilinx: versal: Add feature check API

Add API to check availability of given API in ATF
as well as platform management controller and returns
the supported version number.

Signed-off-by: Ravi Patel <ravi.patel@xilinx.com>
Signed-off-by: Jolly Shah <jolly.shah@xilinx.com>
Change-Id: I608b38f60b36c4d105b7a205ecb8b02de0c00f3c
diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.c b/plat/xilinx/versal/pm_service/pm_api_sys.c
index 216bc98..54fd6e1 100644
--- a/plat/xilinx/versal/pm_service/pm_api_sys.c
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.c
@@ -747,3 +747,73 @@
 			 wkup_device, enable);
 	return pm_ipi_send(primary_proc, payload);
 }
+
+/**
+ * pm_feature_check() - Returns the supported API version if supported
+ * @api_id	API ID to check
+ * @value	Returned supported API version
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_feature_check(uint32_t api_id, unsigned int *version)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT], fw_api_version;
+	uint32_t status;
+
+	switch (api_id) {
+	case PM_GET_CALLBACK_DATA:
+	case PM_GET_TRUSTZONE_VERSION:
+	case PM_INIT_FINALIZE:
+		*version = (PM_API_BASE_VERSION << 16);
+		return PM_RET_SUCCESS;
+	case PM_GET_API_VERSION:
+	case PM_GET_DEVICE_STATUS:
+	case PM_REQ_SUSPEND:
+	case PM_SELF_SUSPEND:
+	case PM_FORCE_POWERDOWN:
+	case PM_ABORT_SUSPEND:
+	case PM_REQ_WAKEUP:
+	case PM_SET_WAKEUP_SOURCE:
+	case PM_SYSTEM_SHUTDOWN:
+	case PM_REQUEST_DEVICE:
+	case PM_RELEASE_DEVICE:
+	case PM_SET_REQUIREMENT:
+	case PM_RESET_ASSERT:
+	case PM_RESET_GET_STATUS:
+	case PM_PINCTRL_REQUEST:
+	case PM_PINCTRL_RELEASE:
+	case PM_PINCTRL_GET_FUNCTION:
+	case PM_PINCTRL_SET_FUNCTION:
+	case PM_PINCTRL_CONFIG_PARAM_GET:
+	case PM_PINCTRL_CONFIG_PARAM_SET:
+	case PM_IOCTL:
+	case PM_QUERY_DATA:
+	case PM_CLOCK_ENABLE:
+	case PM_CLOCK_DISABLE:
+	case PM_CLOCK_GETSTATE:
+	case PM_CLOCK_SETDIVIDER:
+	case PM_CLOCK_GETDIVIDER:
+	case PM_CLOCK_SETPARENT:
+	case PM_CLOCK_GETPARENT:
+	case PM_PLL_SET_PARAMETER:
+	case PM_PLL_GET_PARAMETER:
+	case PM_PLL_SET_MODE:
+	case PM_PLL_GET_MODE:
+	case PM_FEATURE_CHECK:
+		*version = (PM_API_BASE_VERSION << 16);
+		break;
+	default:
+		*version = 0U;
+		return PM_RET_ERROR_NOFEATURE;
+	}
+
+	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_FEATURE_CHECK, api_id);
+
+	status = pm_ipi_send_sync(primary_proc, payload, &fw_api_version, 1);
+	if (status != PM_RET_SUCCESS)
+		return status;
+
+	*version |= fw_api_version;
+
+	return PM_RET_SUCCESS;
+}
diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.h b/plat/xilinx/versal/pm_service/pm_api_sys.h
index 282c175..4e884e0 100644
--- a/plat/xilinx/versal/pm_service/pm_api_sys.h
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.h
@@ -65,5 +65,5 @@
 enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
 				 uint32_t arg3, uint32_t *data);
 unsigned int pm_get_shutdown_scope(void);
-
+enum pm_ret_status pm_feature_check(uint32_t api_id, unsigned int *version);
 #endif /* PM_API_SYS_H */
diff --git a/plat/xilinx/versal/pm_service/pm_defs.h b/plat/xilinx/versal/pm_service/pm_defs.h
index 281494a..a7b0a02 100644
--- a/plat/xilinx/versal/pm_service/pm_defs.h
+++ b/plat/xilinx/versal/pm_service/pm_defs.h
@@ -33,6 +33,12 @@
 				       XPM_NODESUBCL_DEV_PERIPH, \
 				       XPM_NODETYPE_DEV_PERIPH, (IDX))
 
+#define PM_GET_CALLBACK_DATA		0xa01
+#define PM_GET_TRUSTZONE_VERSION	0xa03
+
+/* PM API Versions */
+#define PM_API_BASE_VERSION		1U
+
 /* PM API ids */
 #define PM_GET_API_VERSION		1U
 #define PM_GET_DEVICE_STATUS		3U
@@ -70,6 +76,7 @@
 #define PM_PLL_GET_PARAMETER		49U
 #define PM_PLL_SET_MODE			50U
 #define PM_PLL_GET_MODE			51U
+#define PM_FEATURE_CHECK		63U
 
 /* IOCTL IDs for clock driver */
 #define IOCTL_SET_PLL_FRAC_MODE		8
@@ -121,6 +128,7 @@
  * @PM_RET_SUCCESS:		success
  * @PM_RET_ERROR_ARGS:		illegal arguments provided (deprecated)
  * @PM_RET_ERROR_NOTSUPPORTED:	feature not supported  (deprecated)
+ * @PM_RET_ERROR_NOFEATURE:	feature is not available
  * @PM_RET_ERROR_INTERNAL:	internal error
  * @PM_RET_ERROR_CONFLICT:	conflict
  * @PM_RET_ERROR_ACCESS:	access rights violation
@@ -134,6 +142,7 @@
 	PM_RET_SUCCESS,
 	PM_RET_ERROR_ARGS = 1,
 	PM_RET_ERROR_NOTSUPPORTED = 4,
+	PM_RET_ERROR_NOFEATURE = 19,
 	PM_RET_ERROR_INTERNAL = 2000,
 	PM_RET_ERROR_CONFLICT = 2001,
 	PM_RET_ERROR_ACCESS = 2002,
diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.c b/plat/xilinx/versal/pm_service/pm_svc_main.c
index 8140b66..b5a6783 100644
--- a/plat/xilinx/versal/pm_service/pm_svc_main.c
+++ b/plat/xilinx/versal/pm_service/pm_svc_main.c
@@ -17,9 +17,6 @@
 #include "pm_client.h"
 #include "pm_ipi.h"
 
-#define PM_GET_CALLBACK_DATA		0xa01
-#define PM_GET_TRUSTZONE_VERSION	0xa03
-
 /* pm_up = true - UP, pm_up = false - DOWN */
 static bool pm_up;
 
@@ -293,6 +290,14 @@
 		SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
 			 ((uint64_t)VERSAL_TZ_VERSION << 32));
 
+	case PM_FEATURE_CHECK:
+	{
+		uint32_t version;
+
+		ret = pm_feature_check(pm_arg[0], &version);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)version << 32));
+	}
+
 	default:
 		WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
 		SMC_RET1(handle, SMC_UNK);