plat: send an sgi to communicate to linux

Upon recieving the interrupt send an SGI.
The sgi number is communicated by linux.

Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
Change-Id: Ib8f07ff7132ba5ac202b546914efb16d04820ed3
Signed-off-by: Venkatesh Yadav Abbarapu <venkatesh.abbarapu@xilinx.com>
diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.c b/plat/xilinx/versal/pm_service/pm_api_sys.c
index 4fe3553..15fe187 100644
--- a/plat/xilinx/versal/pm_service/pm_api_sys.c
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.c
@@ -16,6 +16,7 @@
 #include "pm_client.h"
 #include "pm_defs.h"
 #include "pm_svc_main.h"
+#include "../drivers/arm/gic/v3/gicv3_private.h"
 
 /*********************************************************************
  * Target module IDs macros
@@ -23,6 +24,7 @@
 #define LIBPM_MODULE_ID		0x2
 #define LOADER_MODULE_ID	0x7
 
+#define  MODE	0x80000000
 /* default shutdown/reboot scope is system(2) */
 static unsigned int pm_shutdown_scope = XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM;
 
@@ -862,6 +864,7 @@
 				uint32_t flag)
 {
 	uint32_t payload[PAYLOAD_ARG_CNT];
+	int ret;
 
 	switch (ioctl_id) {
 	case IOCTL_SET_PLL_FRAC_MODE:
@@ -872,6 +875,15 @@
 		return pm_pll_set_param(arg1, PM_PLL_PARAM_DATA, arg2, flag);
 	case IOCTL_GET_PLL_FRAC_DATA:
 		return pm_pll_get_param(arg1, PM_PLL_PARAM_DATA, value, flag);
+	case IOCTL_SET_SGI:
+		/* Get the sgi number */
+		ret = pm_register_sgi(arg1);
+		if (ret) {
+			return PM_RET_ERROR_ARGS;
+		}
+		gicd_write_irouter(gicv3_driver_data->gicd_base,
+				PLAT_VERSAL_IPI_IRQ, MODE);
+		return PM_RET_SUCCESS;
 	default:
 		/* Send request to the PMC */
 		PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_IOCTL,
diff --git a/plat/xilinx/versal/pm_service/pm_defs.h b/plat/xilinx/versal/pm_service/pm_defs.h
index 793f750..ccb2617 100644
--- a/plat/xilinx/versal/pm_service/pm_defs.h
+++ b/plat/xilinx/versal/pm_service/pm_defs.h
@@ -92,6 +92,7 @@
 #define	IOCTL_GET_PLL_FRAC_MODE		9
 #define	IOCTL_SET_PLL_FRAC_DATA		10
 #define	IOCTL_GET_PLL_FRAC_DATA		11
+#define	IOCTL_SET_SGI			25
 
 /* Parameter ID for PLL IOCTLs */
 /* Fractional data portion for PLL */
diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.c b/plat/xilinx/versal/pm_service/pm_svc_main.c
index c3d28f5..87ba732 100644
--- a/plat/xilinx/versal/pm_service/pm_svc_main.c
+++ b/plat/xilinx/versal/pm_service/pm_svc_main.c
@@ -17,18 +17,58 @@
 #include "pm_api_sys.h"
 #include "pm_client.h"
 #include "pm_ipi.h"
+#include <drivers/arm/gicv3.h>
+
+#define XSCUGIC_SGIR_EL1_INITID_SHIFT    24U
+#define INVALID_SGI    0xFF
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6)
 
 /* pm_up = true - UP, pm_up = false - DOWN */
 static bool pm_up;
+static unsigned int sgi = INVALID_SGI;
 
 static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle,
 				void *cookie)
 {
+	int cpu;
+	unsigned int reg;
+
 	(void)plat_ic_acknowledge_interrupt();
+	cpu = plat_my_core_pos() + 1;
+
+	if (sgi != INVALID_SGI) {
+		reg = (cpu | (sgi << XSCUGIC_SGIR_EL1_INITID_SHIFT));
+		write_icc_asgi1r_el1(reg);
+	}
 
 	/* Clear FIQ */
 	plat_ic_end_of_interrupt(id);
 
+	return 0;
+}
+
+/**
+ * pm_register_sgi() - PM register the IPI interrupt
+ *
+ * @sgi -  SGI number to be used for communication.
+ * @return	On success, the initialization function must return 0.
+ *		Any other return value will cause the framework to ignore
+ *		the service
+ *
+ * Update the SGI number to be used.
+ *
+ */
+int pm_register_sgi(unsigned int sgi_num)
+{
+	if (sgi != INVALID_SGI) {
+		return -EBUSY;
+	}
+
+	if (sgi_num >= GICV3_MAX_SGI_TARGETS) {
+		return -EINVAL;
+	}
+
+	sgi = sgi_num;
 	return 0;
 }
 
diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.h b/plat/xilinx/versal/pm_service/pm_svc_main.h
index 71329ca..4f8dc2b 100644
--- a/plat/xilinx/versal/pm_service/pm_svc_main.h
+++ b/plat/xilinx/versal/pm_service/pm_svc_main.h
@@ -14,4 +14,5 @@
 			uint64_t x4, void *cookie, void *handle,
 			uint64_t flags);
 
+int pm_register_sgi(unsigned int sgi_num);
 #endif /* PM_SVC_MAIN_H */