arch: mach-k3: common: Add support to shutdown MCU R5 Core 1

During boot, ROM can bring up the MCU R5F cores in either lockstep or
split mode based on X509 certificate flags. If booted in split mode,
core 0 will run DM firmware and second core sits in WFI. Add support to
shut down core 1 so that other firmwares can later be loaded on them.

The shutdown of MCU R5 Core 1 is invoked at A72 SPL init, as by that
time Device Manager (DM) is up and running on R5 Core 0. The shutdown
request of Core 1 is handled by Device Manager itself.

Signed-off-by: Beleswar Padhi <b-padhi@ti.com>
diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index fc230f1..43ff114 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -31,6 +31,11 @@
 #include <dm/uclass-internal.h>
 #include <dm/device-internal.h>
 
+#define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT	0x00000001
+#define PROC_BOOT_STATUS_FLAG_R5_WFI		0x00000002
+#define PROC_ID_MCU_R5FSS0_CORE1		0x02
+#define PROC_BOOT_CFG_FLAG_R5_LOCKSTEP		0x00000100
+
 #include <asm/arch/k3-qos.h>
 
 struct ti_sci_handle *get_ti_sci_handle(void)
@@ -328,3 +333,67 @@
 		writel(qos_data[i].val, (uintptr_t)qos_data[i].reg);
 }
 #endif
+
+int __maybe_unused shutdown_mcu_r5_core1(void)
+{
+	struct ti_sci_handle *ti_sci = get_ti_sci_handle();
+	struct ti_sci_dev_ops *dev_ops = &ti_sci->ops.dev_ops;
+	struct ti_sci_proc_ops *proc_ops = &ti_sci->ops.proc_ops;
+	u32 dev_id_mcu_r5_core1 = put_core_ids[0];
+	u64 boot_vector;
+	u32 cfg, ctrl, sts, halted;
+	int cluster_mode_lockstep, ret;
+	bool r_state = false, c_state = false;
+
+	ret = proc_ops->proc_request(ti_sci, PROC_ID_MCU_R5FSS0_CORE1);
+	if (ret) {
+		printf("Unable to request processor control for MCU1_1 core, %d\n",
+		       ret);
+		return ret;
+	}
+
+	ret = dev_ops->is_on(ti_sci, dev_id_mcu_r5_core1, &r_state, &c_state);
+	if (ret) {
+		printf("Unable to get device status for MCU1_1 core, %d\n", ret);
+		return ret;
+	}
+
+	ret = proc_ops->get_proc_boot_status(ti_sci, PROC_ID_MCU_R5FSS0_CORE1,
+					     &boot_vector, &cfg, &ctrl, &sts);
+	if (ret) {
+		printf("Unable to get Processor boot status for MCU1_1 core, %d\n",
+		       ret);
+		goto release_proc_ctrl;
+	}
+
+	halted = !!(sts & PROC_BOOT_STATUS_FLAG_R5_WFI);
+	cluster_mode_lockstep = !!(cfg & PROC_BOOT_CFG_FLAG_R5_LOCKSTEP);
+
+	/*
+	 * Shutdown MCU R5F Core 1 only if:
+	 *	- cluster is booted in SplitMode
+	 *	- core is powered on
+	 *	- core is in WFI (halted)
+	 */
+	if (cluster_mode_lockstep || !c_state || !halted) {
+		ret = -EINVAL;
+		goto release_proc_ctrl;
+	}
+
+	ret = proc_ops->set_proc_boot_ctrl(ti_sci, PROC_ID_MCU_R5FSS0_CORE1,
+					   PROC_BOOT_CTRL_FLAG_R5_CORE_HALT, 0);
+	if (ret) {
+		printf("Unable to Halt MCU1_1 core, %d\n", ret);
+		goto release_proc_ctrl;
+	}
+
+	ret = dev_ops->put_device(ti_sci, dev_id_mcu_r5_core1);
+	if (ret) {
+		printf("Unable to assert reset on MCU1_1 core, %d\n", ret);
+		return ret;
+	}
+
+release_proc_ctrl:
+	proc_ops->proc_release(ti_sci, PROC_ID_MCU_R5FSS0_CORE1);
+	return ret;
+}