allwinner: Move sunxi_cpu_power_off_self() into platforms

The code to power the current core off when SCPI is not available is now
different for the two supported SoC families.
To make adding new platforms easier, move sunxi_cpu_power_off_self()
into the SoC directory, so we don't need to carry definitions for both
methods for all SoCs.

On the H6 we just need to trigger the CPUIDLE hardware, so can get rid
of all the code to program the ARISC, which is now only needed for the
A64 version.

Change-Id: Id2a1ac7dcb375e2fd021b441575ce86b4d7edf2c
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
diff --git a/plat/allwinner/common/sunxi_common.c b/plat/allwinner/common/sunxi_common.c
index 5b536a0..78f96f2 100644
--- a/plat/allwinner/common/sunxi_common.c
+++ b/plat/allwinner/common/sunxi_common.c
@@ -6,13 +6,9 @@
 
 #include <errno.h>
 
-#include <platform_def.h>
-
-#include <arch_helpers.h>
 #include <common/debug.h>
 #include <lib/mmio.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
-#include <plat/common/platform.h>
 
 #include <sunxi_def.h>
 #include <sunxi_mmap.h>
@@ -154,50 +150,3 @@
 
 	return 0;
 }
-
-/* This lock synchronises access to the arisc management processor. */
-DEFINE_BAKERY_LOCK(arisc_lock);
-
-/*
- * Tell the "arisc" SCP core (an OpenRISC core) to execute some code.
- * We don't have any service running there, so we place some OpenRISC code
- * in SRAM, put the address of that into the reset vector and release the
- * arisc reset line. The SCP will execute that code and pull the line up again.
- */
-void sunxi_execute_arisc_code(uint32_t *code, size_t size, uint16_t param)
-{
-	uintptr_t arisc_reset_vec = SUNXI_SRAM_A2_BASE + 0x100;
-
-	do {
-		bakery_lock_get(&arisc_lock);
-		/* Wait until the arisc is in reset state. */
-		if (!(mmio_read_32(SUNXI_R_CPUCFG_BASE) & BIT(0)))
-			break;
-
-		bakery_lock_release(&arisc_lock);
-	} while (1);
-
-	/* Patch up the code to feed in an input parameter. */
-	code[0] = (code[0] & ~0xffff) | param;
-	clean_dcache_range((uintptr_t)code, size);
-
-	/*
-	 * The OpenRISC unconditional branch has opcode 0, the branch offset
-	 * is in the lower 26 bits, containing the distance to the target,
-	 * in instruction granularity (32 bits).
-	 */
-	mmio_write_32(arisc_reset_vec, ((uintptr_t)code - arisc_reset_vec) / 4);
-	clean_dcache_range(arisc_reset_vec, 4);
-
-	/* De-assert the arisc reset line to let it run. */
-	mmio_setbits_32(SUNXI_R_CPUCFG_BASE, BIT(0));
-
-	/*
-	 * We release the lock here, although the arisc is still busy.
-	 * But as long as it runs, the reset line is high, so other users
-	 * won't leave the loop above.
-	 * Once it has finished, the code is supposed to clear the reset line,
-	 * to signal this to other users.
-	 */
-	bakery_lock_release(&arisc_lock);
-}
diff --git a/plat/allwinner/common/sunxi_cpu_ops.c b/plat/allwinner/common/sunxi_cpu_ops.c
index 43c03ac..420b507 100644
--- a/plat/allwinner/common/sunxi_cpu_ops.c
+++ b/plat/allwinner/common/sunxi_cpu_ops.c
@@ -19,10 +19,6 @@
 #include <sunxi_mmap.h>
 #include <sunxi_private.h>
 
-#ifndef SUNXI_CPUIDLE_EN_REG
-#include <core_off_arisc.h>
-#endif
-
 static void sunxi_cpu_disable_power(unsigned int cluster, unsigned int core)
 {
 	if (mmio_read_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core)) == 0xff)
@@ -67,32 +63,6 @@
 	sunxi_cpu_disable_power(cluster, core);
 }
 
-void sunxi_cpu_power_off_self(void)
-{
-	u_register_t mpidr = read_mpidr();
-	unsigned int core  = MPIDR_AFFLVL0_VAL(mpidr);
-
-	/* Simplifies assembly, all SoCs so far are single cluster anyway. */
-	assert(MPIDR_AFFLVL1_VAL(mpidr) == 0);
-
-#ifdef SUNXI_CPUIDLE_EN_REG
-	/* Enable the CPUIDLE hardware (only really needs to be done once). */
-	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000);
-	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001);
-
-	/* Trigger power off for this core. */
-	mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core));
-#else
-	/*
-	 * If we are supposed to turn ourself off, tell the arisc SCP
-	 * to do that work for us. The code expects the core mask to be
-	 * patched into the first instruction.
-	 */
-	sunxi_execute_arisc_code(arisc_core_off, sizeof(arisc_core_off),
-				 BIT_32(core));
-#endif
-}
-
 void sunxi_cpu_on(u_register_t mpidr)
 {
 	unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
diff --git a/plat/allwinner/sun50i_a64/sunxi_power.c b/plat/allwinner/sun50i_a64/sunxi_power.c
index 80a69c3..0fdb62d 100644
--- a/plat/allwinner/sun50i_a64/sunxi_power.c
+++ b/plat/allwinner/sun50i_a64/sunxi_power.c
@@ -14,6 +14,7 @@
 #include <drivers/allwinner/sunxi_rsb.h>
 #include <lib/mmio.h>
 
+#include <core_off_arisc.h>
 #include <sunxi_def.h>
 #include <sunxi_mmap.h>
 #include <sunxi_private.h>
@@ -205,3 +206,55 @@
 	}
 
 }
+
+/* This lock synchronises access to the arisc management processor. */
+static DEFINE_BAKERY_LOCK(arisc_lock);
+
+/*
+ * If we are supposed to turn ourself off, tell the arisc SCP to do that
+ * work for us. Without any SCPI provider running there, we place some
+ * OpenRISC code into SRAM, put the address of that into the reset vector
+ * and release the arisc reset line. The SCP will wait for the core to enter
+ * WFI, then execute that code and pull the line up again.
+ * The code expects the core mask to be patched into the first instruction.
+ */
+void sunxi_cpu_power_off_self(void)
+{
+	u_register_t mpidr = read_mpidr();
+	unsigned int core  = MPIDR_AFFLVL0_VAL(mpidr);
+	uintptr_t arisc_reset_vec = SUNXI_SRAM_A2_BASE + 0x100;
+	uint32_t *code = arisc_core_off;
+
+	do {
+		bakery_lock_get(&arisc_lock);
+		/* Wait until the arisc is in reset state. */
+		if (!(mmio_read_32(SUNXI_R_CPUCFG_BASE) & BIT(0)))
+			break;
+
+		bakery_lock_release(&arisc_lock);
+	} while (1);
+
+	/* Patch up the code to feed in an input parameter. */
+	code[0] = (code[0] & ~0xffff) | BIT_32(core);
+	clean_dcache_range((uintptr_t)code, sizeof(arisc_core_off));
+
+	/*
+	 * The OpenRISC unconditional branch has opcode 0, the branch offset
+	 * is in the lower 26 bits, containing the distance to the target,
+	 * in instruction granularity (32 bits).
+	 */
+	mmio_write_32(arisc_reset_vec, ((uintptr_t)code - arisc_reset_vec) / 4);
+	clean_dcache_range(arisc_reset_vec, 4);
+
+	/* De-assert the arisc reset line to let it run. */
+	mmio_setbits_32(SUNXI_R_CPUCFG_BASE, BIT(0));
+
+	/*
+	 * We release the lock here, although the arisc is still busy.
+	 * But as long as it runs, the reset line is high, so other users
+	 * won't leave the loop above.
+	 * Once it has finished, the code is supposed to clear the reset line,
+	 * to signal this to other users.
+	 */
+	bakery_lock_release(&arisc_lock);
+}
diff --git a/plat/allwinner/sun50i_h6/include/core_off_arisc.h b/plat/allwinner/sun50i_h6/include/core_off_arisc.h
deleted file mode 100644
index 63a5d8d..0000000
--- a/plat/allwinner/sun50i_h6/include/core_off_arisc.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-static uint32_t arisc_core_off[] = {
-	0x18600000, /* l.movhi	r3, <corenr>	*/
-	0x18000000, /* l.movhi	r0, 0x0		*/
-	0x19a00901, /* l.movhi	r13, 0x901	*/
-	0x84ad0080, /* l.lwz	r5, 0x80(r13)	*/
-	0xe0a51803, /* l.and	r5, r5, r3	*/
-	0xe4050000, /* l.sfeq	r5, r0		*/
-	0x13fffffd, /* l.bf	-12		*/
-	0xb8c30050, /* l.srli	r6, r3, 16	*/
-
-	0xbc060001, /* l.sfeqi	r6, 1		*/
-	0x10000005, /* l.bf	+20		*/
-	0x19a00700, /* l.movhi	r13, 0x700	*/
-	0x84ad0444, /* l.lwz	r5, 0x0444(r13)	*/
-	0xe0a53004, /* l.or	r5, r5, r6	*/
-	0xd40d2c44, /* l.sw	0x0444(r13), r5	*/
-
-	0x84ad0440, /* l.lwz	r5, 0x0440(r13)	*/
-	0xacc6ffff, /* l.xori	r6, r6, -1	*/
-	0xe0a53003, /* l.and	r5, r5, r6	*/
-	0xd40d2c40, /* l.sw	0x0440(r13), r5	*/
-
-	0xe0c3000f, /* l.ff1	r6, r3		*/
-	0x9cc6ffef, /* l.addi	r6, r6, -17	*/
-	0xb8c60002, /* l.slli	r6, r6, 2	*/
-	0xe0c66800, /* l.add	r6, r6, r13	*/
-	0xa8a000ff, /* l.ori	r5, r0, 0xff	*/
-	0xd4062c50, /* l.sw	0x0450(r6), r5	*/
-
-	0xd40d0400, /* l.sw	0x0400(r13), r0	*/
-	0x03ffffff, /* l.j	-1		*/
-	0x15000000, /* l.nop			*/
-};
diff --git a/plat/allwinner/sun50i_h6/sunxi_power.c b/plat/allwinner/sun50i_h6/sunxi_power.c
index a7865a5..d298e6b 100644
--- a/plat/allwinner/sun50i_h6/sunxi_power.c
+++ b/plat/allwinner/sun50i_h6/sunxi_power.c
@@ -10,7 +10,9 @@
 #include <common/debug.h>
 #include <drivers/allwinner/axp.h>
 #include <drivers/allwinner/sunxi_rsb.h>
+#include <lib/mmio.h>
 
+#include <sunxi_cpucfg.h>
 #include <sunxi_def.h>
 #include <sunxi_mmap.h>
 #include <sunxi_private.h>
@@ -102,3 +104,16 @@
 		break;
 	}
 }
+
+void sunxi_cpu_power_off_self(void)
+{
+	u_register_t mpidr = read_mpidr();
+	unsigned int core  = MPIDR_AFFLVL0_VAL(mpidr);
+
+	/* Enable the CPUIDLE hardware (only really needs to be done once). */
+	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000);
+	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001);
+
+	/* Trigger power off for this core. */
+	mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core));
+}