arm64: zynqmp: dynamically mark r5 cores as used

When Linux boot takes over control of the pmu
(by signaling PM_INIT_FINALIZE via ipi), pmu will switch off 'unused'
rpu cores. The Xilinx zynqmp fsbl prevents switching off those cores by
marking rpu cores as 'used' when loading code partitions to those cores.
The current u-boot SPL is missing this behaviour, which results in
halting rpu cores during Linux boot.

This commit mimics the xilinx zynqmp fsbl behavior by marking r5 cores as
used when they are released during boot.

Signed-off-by: Lukas Funke <lukas.funke@weidmueller.com>
Signed-off-by: Lukas Funke <lukas.funke-oss@weidmueller.com>
Link: https://lore.kernel.org/r/20221028121547.26464-2-lukas.funke-oss@weidmueller.com
Signed-off-by: Michal Simek <michal.simek@amd.com>
diff --git a/arch/arm/mach-zynqmp/mp.c b/arch/arm/mach-zynqmp/mp.c
index 949456d..2891878 100644
--- a/arch/arm/mach-zynqmp/mp.c
+++ b/arch/arm/mach-zynqmp/mp.c
@@ -42,6 +42,9 @@
 
 #define ZYNQMP_MAX_CORES	6
 
+#define ZYNQMP_RPU0_USE_MASK BIT(1)
+#define ZYNQMP_RPU1_USE_MASK BIT(2)
+
 int is_core_valid(unsigned int core)
 {
 	if (core < ZYNQMP_MAX_CORES)
@@ -248,6 +251,27 @@
 		enable_clock_r5();
 		release_r5_reset(ZYNQMP_CORE_RPU1, SPLIT);
 	}
+}
+
+static void mark_r5_used(u32 nr, u8 mode)
+{
+	u32 mask = 0;
+
+	if (mode == LOCK) {
+		mask = ZYNQMP_RPU0_USE_MASK | ZYNQMP_RPU1_USE_MASK;
+	} else {
+		switch (nr) {
+		case ZYNQMP_CORE_RPU0:
+			mask = ZYNQMP_RPU0_USE_MASK;
+			break;
+		case ZYNQMP_CORE_RPU1:
+			mask = ZYNQMP_RPU1_USE_MASK;
+			break;
+		default:
+			return;
+		}
+	}
+	zynqmp_mmio_write((ulong)&pmu_base->gen_storage4, mask, mask);
 }
 
 int cpu_release(u32 nr, int argc, char *const argv[])
@@ -305,6 +329,7 @@
 			write_tcm_boot_trampoline(boot_addr_uniq);
 			dcache_enable();
 			set_r5_halt_mode(nr, RELEASE, LOCK);
+			mark_r5_used(nr, LOCK);
 		} else if (!strncmp(argv[1], "split", 5)) {
 			printf("R5 split mode\n");
 			set_r5_reset(nr, SPLIT);
@@ -317,6 +342,7 @@
 			write_tcm_boot_trampoline(boot_addr_uniq);
 			dcache_enable();
 			set_r5_halt_mode(nr, RELEASE, SPLIT);
+			mark_r5_used(nr, SPLIT);
 		} else {
 			printf("Unsupported mode\n");
 			return 1;