plat: xilinx: zynqmp: Add checksum support for IPI data

This patch adds support for CRC checksum for IPI data when the
macro ZYNQMP_IPI_CRC_CHECK is defined.

Signed-off-by: Venkatesh Yadav Abbarapu <venkatesh.abbarapu@xilinx.com>
Signed-off-by: Jolly Shah <jolly.shah@xilinx.com>
Change-Id: Ic981f162666b3c1fffeb1b9fef3ee7714ecd889d
diff --git a/plat/xilinx/common/include/pm_ipi.h b/plat/xilinx/common/include/pm_ipi.h
index 16db5c5..7bcf596 100644
--- a/plat/xilinx/common/include/pm_ipi.h
+++ b/plat/xilinx/common/include/pm_ipi.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -26,5 +26,8 @@
 void pm_ipi_irq_enable(const struct pm_proc *proc);
 void pm_ipi_irq_clear(const struct pm_proc *proc);
 uint32_t pm_ipi_irq_status(const struct pm_proc *proc);
+#if ZYNQMP_IPI_CRC_CHECK
+uint32_t calculate_crc(uint32_t payload[PAYLOAD_ARG_CNT], uint32_t buffersize);
+#endif
 
 #endif /* PM_IPI_H */
diff --git a/plat/xilinx/common/pm_service/pm_ipi.c b/plat/xilinx/common/pm_service/pm_ipi.c
index 034cd5b..c83d25b 100644
--- a/plat/xilinx/common/pm_service/pm_ipi.c
+++ b/plat/xilinx/common/pm_service/pm_ipi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -57,6 +57,9 @@
 	uintptr_t buffer_base = proc->ipi->buffer_base +
 					IPI_BUFFER_TARGET_REMOTE_OFFSET +
 					IPI_BUFFER_REQ_OFFSET;
+#if ZYNQMP_IPI_CRC_CHECK
+	payload[PAYLOAD_CRC_POS] = calculate_crc(payload, IPI_W0_TO_W6_SIZE);
+#endif
 
 	/* Write payload into IPI buffer */
 	for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) {
@@ -132,6 +135,10 @@
 					   unsigned int *value, size_t count)
 {
 	size_t i;
+#if ZYNQMP_IPI_CRC_CHECK
+	size_t j;
+	unsigned int response_payload[PAYLOAD_ARG_CNT];
+#endif
 	uintptr_t buffer_base = proc->ipi->buffer_base +
 				IPI_BUFFER_TARGET_REMOTE_OFFSET +
 				IPI_BUFFER_RESP_OFFSET;
@@ -147,6 +154,16 @@
 		*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
 		value++;
 	}
+#if ZYNQMP_IPI_CRC_CHECK
+	for (j = 0; j < PAYLOAD_ARG_CNT; j++)
+		response_payload[j] = mmio_read_32(buffer_base +
+						(j * PAYLOAD_ARG_SIZE));
+
+	if (response_payload[PAYLOAD_CRC_POS] !=
+			calculate_crc(response_payload, IPI_W0_TO_W6_SIZE))
+		NOTICE("ERROR in CRC response payload value:0x%x\n",
+					response_payload[PAYLOAD_CRC_POS]);
+#endif
 
 	return mmio_read_32(buffer_base);
 }
@@ -162,6 +179,10 @@
 void pm_ipi_buff_read_callb(unsigned int *value, size_t count)
 {
 	size_t i;
+#if ZYNQMP_IPI_CRC_CHECK
+	size_t j;
+	unsigned int response_payload[PAYLOAD_ARG_CNT];
+#endif
 	uintptr_t buffer_base = IPI_BUFFER_REMOTE_BASE +
 				IPI_BUFFER_TARGET_LOCAL_OFFSET +
 				IPI_BUFFER_REQ_OFFSET;
@@ -173,6 +194,16 @@
 		*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
 		value++;
 	}
+#if ZYNQMP_IPI_CRC_CHECK
+	for (j = 0; j < PAYLOAD_ARG_CNT; j++)
+		response_payload[j] = mmio_read_32(buffer_base +
+						(j * PAYLOAD_ARG_SIZE));
+
+	if (response_payload[PAYLOAD_CRC_POS] !=
+			calculate_crc(response_payload, IPI_W0_TO_W6_SIZE))
+		NOTICE("ERROR in CRC response payload value:0x%x\n",
+					response_payload[PAYLOAD_CRC_POS]);
+#endif
 }
 
 /**
@@ -228,3 +259,34 @@
 	else
 		return 0;
 }
+
+#if ZYNQMP_IPI_CRC_CHECK
+uint32_t calculate_crc(uint32_t *payload, uint32_t bufsize)
+{
+	uint32_t crcinit = CRC_INIT_VALUE;
+	uint32_t order   = CRC_ORDER;
+	uint32_t polynom = CRC_POLYNOM;
+	uint32_t i, j, c, bit, datain, crcmask, crchighbit;
+	uint32_t crc = crcinit;
+
+	crcmask = ((uint32_t)((1U << (order - 1U)) - 1U) << 1U) | 1U;
+	crchighbit = (uint32_t)(1U << (order - 1U));
+
+	for (i = 0U; i < bufsize; i++) {
+		datain = mmio_read_8((unsigned long)payload + i);
+		c = datain;
+		j = 0x80U;
+		while (j != 0U) {
+			bit = crc & crchighbit;
+			crc <<= 1U;
+			if (0U != (c & j))
+				bit ^= crchighbit;
+			if (bit != 0U)
+				crc ^= polynom;
+			j >>= 1U;
+		}
+		crc &= crcmask;
+	}
+	return crc;
+}
+#endif
diff --git a/plat/xilinx/zynqmp/include/plat_pm_common.h b/plat/xilinx/zynqmp/include/plat_pm_common.h
index 1b371cc..56a747a 100644
--- a/plat/xilinx/zynqmp/include/plat_pm_common.h
+++ b/plat/xilinx/zynqmp/include/plat_pm_common.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -16,7 +16,16 @@
 #include <common/debug.h>
 #include "pm_defs.h"
 
-#define PAYLOAD_ARG_CNT		6U
+#if ZYNQMP_IPI_CRC_CHECK
+#define PAYLOAD_ARG_CNT         8U
+#define IPI_W0_TO_W6_SIZE       28U
+#define PAYLOAD_CRC_POS         7U
+#define CRC_INIT_VALUE          0x4F4EU
+#define CRC_ORDER               16U
+#define CRC_POLYNOM             0x8005U
+#else
+#define PAYLOAD_ARG_CNT         6U
+#endif
 #define PAYLOAD_ARG_SIZE	4U	/* size in bytes */
 
 #define ZYNQMP_TZ_VERSION_MAJOR		1
diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk
index c34a516..1039e27 100644
--- a/plat/xilinx/zynqmp/platform.mk
+++ b/plat/xilinx/zynqmp/platform.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
@@ -9,6 +9,7 @@
 A53_DISABLE_NON_TEMPORAL_HINT := 0
 SEPARATE_CODE_AND_RODATA := 1
 ZYNQMP_WDT_RESTART := 0
+ZYNQMP_IPI_CRC_CHECK := 0
 override RESET_TO_BL31 := 1
 
 # Do not enable SVE
@@ -45,7 +46,12 @@
 $(eval $(call add_define,ZYNQMP_WDT_RESTART))
 endif
 
-PLAT_INCLUDES		:=	-Iinclude/plat/arm/common/aarch64/		\
+ifdef ZYNQMP_IPI_CRC_CHECK
+    $(eval $(call add_define,ZYNQMP_IPI_CRC_CHECK))
+endif
+
+PLAT_INCLUDES		:=	-Iinclude/plat/arm/common/			\
+				-Iinclude/plat/arm/common/aarch64/		\
 				-Iplat/xilinx/common/include/			\
 				-Iplat/xilinx/zynqmp/include/			\
 				-Iplat/xilinx/zynqmp/pm_service/		\