feat(intel): implementation of SiPSVC-V3 protocol framework

- Develop SiPSVC-V3 framework to support async/yielding SMC calls.
- Add support for multi clients with multiple jobs running together.
- Add support for SDM doorbell interrupt handling.
- Keep the framework backward compatible with V1 clients.
- Enable the framework on all the platform Agilex7, Agilex5, N5X,
  and Stratix10.

Change-Id: I9eb61c48be89867b4227e084493bfcf67cbe7924
Signed-off-by: Girisha Dengi <girisha.dengi@intel.com>
Signed-off-by: Sieu Mun Tang <sieu.mun.tang@altera.com>
diff --git a/plat/intel/soc/common/socfpga_sip_svc.c b/plat/intel/soc/common/socfpga_sip_svc.c
index d64ead7..703a778 100644
--- a/plat/intel/soc/common/socfpga_sip_svc.c
+++ b/plat/intel/soc/common/socfpga_sip_svc.c
@@ -801,6 +801,128 @@
 }
 #endif
 
+#if SIP_SVC_V3
+uint8_t sip_smc_cmd_cb_ret3(void *resp_desc, void *cmd_desc, uint32_t *ret_args)
+{
+	uint8_t ret_args_len = 0U;
+	sdm_response_t *resp = (sdm_response_t *)resp_desc;
+	sdm_command_t *cmd = (sdm_command_t *)cmd_desc;
+
+	(void)cmd;
+	/* Returns 3 SMC arguments for SMC_RET3 */
+	ret_args[ret_args_len++] = INTEL_SIP_SMC_STATUS_OK;
+	ret_args[ret_args_len++] = resp->err_code;
+	ret_args[ret_args_len++] = resp->resp_data[0];
+
+	return ret_args_len;
+}
+
+static uintptr_t smc_ret(void *handle, uint32_t *ret_args, uint32_t ret_args_len)
+{
+	switch (ret_args_len) {
+	case SMC_RET_ARGS_ONE:
+		SMC_RET1(handle, ret_args[0]);
+		break;
+
+	case SMC_RET_ARGS_TWO:
+		SMC_RET2(handle, ret_args[0], ret_args[1]);
+		break;
+
+	case SMC_RET_ARGS_THREE:
+		SMC_RET3(handle, ret_args[0], ret_args[1], ret_args[2]);
+		break;
+
+	case SMC_RET_ARGS_FOUR:
+		SMC_RET4(handle, ret_args[0], ret_args[1], ret_args[2], ret_args[3]);
+		break;
+
+	case SMC_RET_ARGS_FIVE:
+		SMC_RET5(handle, ret_args[0], ret_args[1], ret_args[2], ret_args[3], ret_args[4]);
+		break;
+
+	default:
+		SMC_RET1(handle, INTEL_SIP_SMC_STATUS_ERROR);
+		break;
+	}
+}
+
+/*
+ * This function is responsible for handling all SiP SVC V3 calls from the
+ * non-secure world.
+ */
+static uintptr_t sip_smc_handler_v3(uint32_t smc_fid,
+				    u_register_t x1,
+				    u_register_t x2,
+				    u_register_t x3,
+				    u_register_t x4,
+				    void *cookie,
+				    void *handle,
+				    u_register_t flags)
+{
+	int status = 0;
+
+	VERBOSE("MBOX: SVC-V3: x0 0x%x, x1 0x%lx, x2 0x%lx, x3 0x%lx, x4 0x%lx\n",
+		smc_fid, x1, x2, x3, x4);
+
+	switch (smc_fid) {
+	case ALTERA_SIP_SMC_ASYNC_RESP_POLL:
+	{
+		uint32_t ret_args[8] = {0};		/* X0 to X7 return arguments */
+		uint32_t ret_args_len;
+
+		status = mailbox_response_poll_v3(GET_CLIENT_ID(x1),
+						  GET_JOB_ID(x1),
+						  ret_args,
+						  &ret_args_len);
+		/* Always reserve [0] index for command status. */
+		ret_args[0] = status;
+
+		/* Return SMC call based on the number of return arguments */
+		return smc_ret(handle, ret_args, ret_args_len);
+	}
+
+	case ALTERA_SIP_SMC_ASYNC_RESP_POLL_ON_INTR:
+	{
+		uint8_t client_id = 0U;
+		uint8_t job_id = 0U;
+		uint64_t trans_id_bitmap[4] = {0U};
+
+		status = mailbox_response_poll_on_intr_v3(&client_id,
+							  &job_id,
+							  trans_id_bitmap);
+
+		SMC_RET5(handle, status, trans_id_bitmap[0], trans_id_bitmap[1],
+			 trans_id_bitmap[2], trans_id_bitmap[3]);
+		break;
+	}
+
+	case ALTERA_SIP_SMC_ASYNC_HWMON_READVOLT:
+	case ALTERA_SIP_SMC_ASYNC_HWMON_READTEMP:
+	{
+		uint32_t channel = (uint32_t)x2;
+		uint32_t mbox_cmd = ((smc_fid == ALTERA_SIP_SMC_ASYNC_HWMON_READVOLT) ?
+					MBOX_HWMON_READVOLT : MBOX_HWMON_READTEMP);
+
+		status = mailbox_send_cmd_async_v3(GET_CLIENT_ID(x1),
+						   GET_JOB_ID(x1),
+						   mbox_cmd,
+						   &channel,
+						   1U,
+						   MBOX_CMD_FLAG_CASUAL,
+						   sip_smc_cmd_cb_ret3,
+						   NULL,
+						   0);
+
+		SMC_RET1(handle, status);
+	}
+
+	default:
+		return socfpga_sip_handler(smc_fid, x1, x2, x3, x4,
+					   cookie, handle, flags);
+	} /* switch (smc_fid) */
+}
+#endif
+
 /*
  * This function is responsible for handling all SiP calls from the NS world
  */
@@ -1375,7 +1497,16 @@
 	    cmd <= INTEL_SIP_SMC_CMD_V2_RANGE_END) {
 		return sip_smc_handler_v2(smc_fid, x1, x2, x3, x4,
 			cookie, handle, flags);
-	} else {
+	}
+#if SIP_SVC_V3
+	else if ((cmd >= INTEL_SIP_SMC_CMD_V3_RANGE_BEGIN) &&
+		(cmd <= INTEL_SIP_SMC_CMD_V3_RANGE_END)) {
+		uintptr_t ret = sip_smc_handler_v3(smc_fid, x1, x2, x3, x4,
+						   cookie, handle, flags);
+		return ret;
+	}
+#endif
+	else {
 		return sip_smc_handler_v1(smc_fid, x1, x2, x3, x4,
 			cookie, handle, flags);
 	}