zynqmp: pm: Implement PLL get parameter EEMI API

This API will be used to get a parameter for the PLL. Parameter values
represent the values as defined in the Zynq MPSoC register reference
manual ug1087.

Signed-off-by: Mirela Simonovic <mirela.simonovic@aggios.com>
Acked-by: Will Wong <WILLW@xilinx.com>
Signed-off-by: Jolly Shah <jollys@xilinx.com>
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
index 9bc11f2..da16691 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
@@ -1268,3 +1268,31 @@
 	PM_PACK_PAYLOAD4(payload, PM_PLL_SET_PARAMETER, nid, param_id, value);
 	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
 }
+
+/**
+ * pm_pll_get_parameter() - Get the PLL parameter value
+ * @nid		Node id of the target PLL
+ * @param_id	ID of the PLL parameter
+ * @value	Location to store the parameter value
+ *
+ * @return	Error if an argument is not valid or status as returned by the
+ *		PM controller (PMU)
+ */
+enum pm_ret_status pm_pll_get_parameter(enum pm_node_id nid,
+					enum pm_pll_param param_id,
+					unsigned int *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Check if given node ID is a PLL node */
+	if (nid < NODE_APLL || nid > NODE_IOPLL)
+		return PM_RET_ERROR_ARGS;
+
+	/* Check if parameter ID is valid and return an error if it's not */
+	if (param_id >= PM_PLL_PARAM_MAX)
+		return PM_RET_ERROR_ARGS;
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD3(payload, PM_PLL_GET_PARAMETER, nid, param_id);
+	return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
index acef490..8ef210a 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
@@ -180,4 +180,8 @@
 				enum pm_pll_param param_id,
 				unsigned int value);
 
+enum pm_ret_status pm_pll_get_parameter(enum pm_node_id nid,
+				enum pm_pll_param param_id,
+				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 fe965c5..167a733 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_defs.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h
@@ -94,6 +94,7 @@
 	PM_SECURE_AES,
 	/* PLL control API functions */
 	PM_PLL_SET_PARAMETER,
+	PM_PLL_GET_PARAMETER,
 	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 7430110..4e4a3ef 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
@@ -567,6 +567,14 @@
 		ret = pm_pll_set_parameter(pm_arg[0], pm_arg[1], pm_arg[2]);
 		SMC_RET1(handle, (uint64_t)ret);
 
+	case PM_PLL_GET_PARAMETER:
+	{
+		uint32_t value;
+
+		ret = pm_pll_get_parameter(pm_arg[0], pm_arg[1], &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);