msm_shared: scm: add support for armv8 register width mode switch

The appropriate register width for the kernel to be booted
may not match the current armv8 execution mode. Utilize
exception level change through secure monitor to request
the register width setting during an exception return, instead
of using a regular branch.

Change-Id: I004c12a1889ce53013da4860d9bea13f7597c941
diff --git a/platform/msm_shared/scm.c b/platform/msm_shared/scm.c
index db09374..4294168 100644
--- a/platform/msm_shared/scm.c
+++ b/platform/msm_shared/scm.c
@@ -606,3 +606,40 @@
 
 	return ret;
 }
+
+/* Execption Level exec secure-os call
+ * Jumps to kernel via secure-os and does not return
+ * on successful jump. System parameters are setup &
+ * passed on to secure-os and are utilized to boot the
+ * kernel.
+ *
+ @ kernel_entry	: kernel entry point passed in as link register.
+ @ dtb_offset	: dt blob address passed in as w0.
+ @ svc_id	: indicates direction of switch 32->64 or 64->32
+ *
+ * Assumes all sanity checks have been performed on arguments.
+ */
+
+void scm_elexec_call(paddr_t kernel_entry, paddr_t dtb_offset)
+{
+	uint32_t svc_id = SCM_SVC_MILESTONE_32_64_ID;
+	uint32_t cmd_id = SCM_SVC_MILESTONE_CMD_ID;
+	void *cmd_buf;
+	size_t cmd_len;
+	static el1_system_param param;
+
+	param.el1_x0 = dtb_offset;
+	param.el1_elr = kernel_entry;
+
+	/* Command Buffer */
+	cmd_buf = (void *)&param;
+	cmd_len = sizeof(el1_system_param);
+
+	/* Response Buffer = Null as no response expected */
+	dprintf(INFO, "Jumping to kernel via monitor\n");
+	scm_call(svc_id, cmd_id, cmd_buf, cmd_len, NULL, 0);
+
+	/* Assert if execution ever reaches here */
+	dprintf(CRITICAL, "Failed to jump to kernel\n");
+	ASSERT(0);
+}