feat(intel): support IO96B ECC Error Injection via SMC call

Add SMC call for IO96B ECC error injection, write dummy data
to DDR and read back. This is required to do from ATF,because
the error injection from Linux kernel is causing inconsitent
behaviour and sometimes causing memory crash.

Change-Id: I62f9dca319ea6a7ddbdbb7cc2965a0a4e2d41ab6
Signed-off-by: Rabara, Niravkumar L <niravkumar.l.rabara@intel.com>
Signed-off-by: Girisha Dengi <girisha.dengi@intel.com>
Signed-off-by: Jit Loon Lim <jit.loon.lim@altera.com>
diff --git a/plat/intel/soc/common/include/socfpga_sip_svc.h b/plat/intel/soc/common/include/socfpga_sip_svc.h
index 7f96adb..fdd1bf8 100644
--- a/plat/intel/soc/common/include/socfpga_sip_svc.h
+++ b/plat/intel/soc/common/include/socfpga_sip_svc.h
@@ -153,6 +153,9 @@
 /* ATF build version */
 #define INTEL_SIP_SMC_ATF_BUILD_VER					0xC200009B
 
+/* IO96B ECC Error Injection */
+#define INTEL_SIP_SMC_INJECT_IO96B_ECC_ERR				0xC200009C
+
 #define INTEL_SIP_SMC_FCS_SHA_MODE_MASK					0xF
 #define INTEL_SIP_SMC_FCS_DIGEST_SIZE_MASK				0xF
 #define INTEL_SIP_SMC_FCS_DIGEST_SIZE_OFFSET				4U
@@ -163,6 +166,8 @@
 #define SYSMGR_ECC_DBE_COLD_RST_MASK					(SYSMGR_ECC_OCRAM_MASK |\
 									SYSMGR_ECC_DDR0_MASK |\
 									SYSMGR_ECC_DDR1_MASK)
+#define IOSSM_ECC_ERR_INJ_DELAY_USECS					(40U)
+#define IOSSM_CMD_STATUS_RESP_READY					BIT(0)
 
 /* Non-mailbox SMC Call */
 #define INTEL_SIP_SMC_SVC_VERSION					0xC2000200
diff --git a/plat/intel/soc/common/socfpga_sip_svc.c b/plat/intel/soc/common/socfpga_sip_svc.c
index f4a3ea0..89e0dd4 100644
--- a/plat/intel/soc/common/socfpga_sip_svc.c
+++ b/plat/intel/soc/common/socfpga_sip_svc.c
@@ -9,6 +9,7 @@
 #include <assert.h>
 #include <common/debug.h>
 #include <common/runtime_svc.h>
+#include <drivers/delay_timer.h>
 #include <lib/mmio.h>
 #include <tools_share/uuid.h>
 
@@ -799,6 +800,22 @@
 	}
 	return INTEL_SIP_SMC_STATUS_OK;
 }
+
+static void intel_inject_io96b_ecc_err(const uint32_t *syndrome, const uint32_t command)
+{
+	volatile uint64_t atf_ddr_buffer;
+	volatile uint64_t val;
+
+	mmio_write_32(IOSSM_CMD_PARAM, *syndrome);
+	mmio_write_32(IOSSM_CMD_TRIG_OP, command);
+	udelay(IOSSM_ECC_ERR_INJ_DELAY_USECS);
+	atf_ddr_buffer = 0xCAFEBABEFEEDFACE;	/* Write data */
+	memcpy_s((void *)&val, sizeof(val),
+		 (void *)&atf_ddr_buffer, sizeof(atf_ddr_buffer));
+
+	/* Clear response_ready BIT0 of status_register before sending next command. */
+	mmio_clrbits_32(IOSSM_CMD_RESP_STATUS, IOSSM_CMD_STATUS_RESP_READY);
+}
 #endif
 
 #if SIP_SVC_V3
@@ -2194,6 +2211,12 @@
 		SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK, VERSION_MAJOR,
 			 VERSION_MINOR, VERSION_PATCH);
 
+#if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5
+	case INTEL_SIP_SMC_INJECT_IO96B_ECC_ERR:
+		intel_inject_io96b_ecc_err((uint32_t *)&x1, (uint32_t)x2);
+		SMC_RET1(handle, INTEL_SIP_SMC_STATUS_OK);
+#endif
+
 	default:
 		return socfpga_sip_handler(smc_fid, x1, x2, x3, x4,
 			cookie, handle, flags);