allwinner: Add Allwinner H616 SoC support

The new Allwinner H616 SoC lacks the management controller and the secure
SRAM A2, so we need to tweak the memory map quite substantially:
We run BL31 in DRAM. Since the DRAM starts at 1GB, we cannot use our
compressed virtual address space (max 256MB) anymore, so we revert to
the full 32bit VA space and use a flat mapping throughout all of it.

The missing controller also means we need to always use the native PSCI
ops, using the CPUIDLE hardware, as SCPI and suspend depend on the ARISC.

Change-Id: I77169b452cb7f5dc2ef734f3fc6e5d931749141d
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
diff --git a/plat/allwinner/common/include/platform_def.h b/plat/allwinner/common/include/platform_def.h
index 3145fea..4893368 100644
--- a/plat/allwinner/common/include/platform_def.h
+++ b/plat/allwinner/common/include/platform_def.h
@@ -17,6 +17,15 @@
 #define SUNXI_SCP_SIZE			0x4000
 
 #ifdef SUNXI_BL31_IN_DRAM
+
+#define BL31_BASE			SUNXI_DRAM_BASE
+#define BL31_LIMIT			(SUNXI_DRAM_BASE + 0x40000)
+
+#define MAX_XLAT_TABLES			4
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+
+#define SUNXI_BL33_VIRT_BASE		PRELOADED_BL33_BASE
+
 #else	/* !SUNXI_BL31_IN_DRAM */
 
 #define BL31_BASE			(SUNXI_SRAM_A2_BASE + 0x4000)
diff --git a/plat/allwinner/common/sunxi_common.c b/plat/allwinner/common/sunxi_common.c
index 3d3a761..27321cc 100644
--- a/plat/allwinner/common/sunxi_common.c
+++ b/plat/allwinner/common/sunxi_common.c
@@ -127,7 +127,7 @@
 	}
 
 	/* un-gate R_PIO clock */
-	if (socid != SUNXI_SOC_H6)
+	if (socid != SUNXI_SOC_H6 && socid != SUNXI_SOC_H616)
 		mmio_setbits_32(SUNXI_R_PRCM_BASE + 0x28, BIT(0));
 
 	/* switch pins PL0 and PL1 to the desired function */
@@ -140,7 +140,7 @@
 	mmio_clrsetbits_32(SUNXI_R_PIO_BASE + 0x1c, 0x0fU, 0x5U);
 
 	/* un-gate clock */
-	if (socid != SUNXI_SOC_H6)
+	if (socid != SUNXI_SOC_H6 && socid != SUNXI_SOC_H616)
 		mmio_setbits_32(SUNXI_R_PRCM_BASE + 0x28, device_bit);
 	else
 		mmio_setbits_32(SUNXI_R_PRCM_BASE + reset_offset, BIT(0));
diff --git a/plat/allwinner/sun50i_h616/include/sunxi_ccu.h b/plat/allwinner/sun50i_h616/include/sunxi_ccu.h
new file mode 100644
index 0000000..85fbb90
--- /dev/null
+++ b/plat/allwinner/sun50i_h616/include/sunxi_ccu.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_CCU_H
+#define SUNXI_CCU_H
+
+#define SUNXI_CCU_SEC_SWITCH_REG	(SUNXI_CCU_BASE + 0x0f00)
+
+#define SUNXI_R_PRCM_SEC_SWITCH_REG	(SUNXI_R_PRCM_BASE + 0x0290)
+
+#endif /* SUNXI_CCU_H */
diff --git a/plat/allwinner/sun50i_h616/include/sunxi_cpucfg.h b/plat/allwinner/sun50i_h616/include/sunxi_cpucfg.h
new file mode 100644
index 0000000..a637554
--- /dev/null
+++ b/plat/allwinner/sun50i_h616/include/sunxi_cpucfg.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_CPUCFG_H
+#define SUNXI_CPUCFG_H
+
+#include <sunxi_mmap.h>
+
+/* c = cluster, n = core */
+#define SUNXI_CPUCFG_CLS_CTRL_REG0(c)	(SUNXI_CPUCFG_BASE + 0x0010 + (c) * 0x10)
+#define SUNXI_CPUCFG_CLS_CTRL_REG1(c)	(SUNXI_CPUCFG_BASE + 0x0014 + (c) * 0x10)
+#define SUNXI_CPUCFG_CACHE_CFG_REG	(SUNXI_CPUCFG_BASE + 0x0024)
+#define SUNXI_CPUCFG_DBG_REG0		(SUNXI_CPUCFG_BASE + 0x00c0)
+
+#define SUNXI_CPUCFG_RST_CTRL_REG(c)	(SUNXI_CPUCFG_BASE + 0x0000 + (c) * 4)
+#define SUNXI_CPUCFG_RVBAR_LO_REG(n)	(SUNXI_CPUCFG_BASE + 0x0040 + (n) * 8)
+#define SUNXI_CPUCFG_RVBAR_HI_REG(n)	(SUNXI_CPUCFG_BASE + 0x0044 + (n) * 8)
+
+#define SUNXI_POWERON_RST_REG(c)	(SUNXI_R_CPUCFG_BASE + 0x0040 + (c) * 4)
+#define SUNXI_POWEROFF_GATING_REG(c)	(SUNXI_R_CPUCFG_BASE + 0x0044 + (c) * 4)
+#define SUNXI_CPU_POWER_CLAMP_REG(c, n)	(SUNXI_R_CPUCFG_BASE + 0x0050 + \
+					(c) * 0x10 + (n) * 4)
+
+#define SUNXI_CPUIDLE_EN_REG		(SUNXI_R_CPUCFG_BASE + 0x0100)
+#define SUNXI_CORE_CLOSE_REG		(SUNXI_R_CPUCFG_BASE + 0x0104)
+#define SUNXI_PWR_SW_DELAY_REG		(SUNXI_R_CPUCFG_BASE + 0x0140)
+#define SUNXI_CONFIG_DELAY_REG		(SUNXI_R_CPUCFG_BASE + 0x0144)
+
+#endif /* SUNXI_CPUCFG_H */
diff --git a/plat/allwinner/sun50i_h616/include/sunxi_mmap.h b/plat/allwinner/sun50i_h616/include/sunxi_mmap.h
new file mode 100644
index 0000000..3b4f4a0
--- /dev/null
+++ b/plat/allwinner/sun50i_h616/include/sunxi_mmap.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_MMAP_H
+#define SUNXI_MMAP_H
+
+/* Memory regions */
+#define SUNXI_ROM_BASE			0x00000000
+#define SUNXI_ROM_SIZE			0x00010000
+#define SUNXI_SRAM_BASE			0x00020000
+#define SUNXI_SRAM_SIZE			0x00038000
+#define SUNXI_SRAM_A1_BASE		0x00020000
+#define SUNXI_SRAM_A1_SIZE		0x00008000
+#define SUNXI_SRAM_C_BASE		0x00028000
+#define SUNXI_SRAM_C_SIZE		0x00030000
+#define SUNXI_DEV_BASE			0x01000000
+#define SUNXI_DEV_SIZE			0x09000000
+#define SUNXI_DRAM_BASE			0x40000000
+#define SUNXI_DRAM_VIRT_BASE		SUNXI_DRAM_BASE
+
+/* Memory-mapped devices */
+#define SUNXI_SYSCON_BASE		0x03000000
+#define SUNXI_CCU_BASE			0x03001000
+#define SUNXI_DMA_BASE			0x03002000
+#define SUNXI_SID_BASE			0x03006000
+#define SUNXI_SPC_BASE			0x03008000
+#define SUNXI_WDOG_BASE			0x030090a0
+#define SUNXI_PIO_BASE			0x0300b000
+#define SUNXI_GICD_BASE			0x03021000
+#define SUNXI_GICC_BASE			0x03022000
+#define SUNXI_UART0_BASE		0x05000000
+#define SUNXI_SPI0_BASE			0x05010000
+#define SUNXI_R_CPUCFG_BASE		0x07000400
+#define SUNXI_R_PRCM_BASE		0x07010000
+//#define SUNXI_R_WDOG_BASE		0x07020400
+#define SUNXI_R_WDOG_BASE		SUNXI_WDOG_BASE
+#define SUNXI_R_PIO_BASE		0x07022000
+#define SUNXI_R_UART_BASE		0x07080000
+#define SUNXI_R_I2C_BASE		0x07081400
+#define SUNXI_R_RSB_BASE		0x07083000
+#define SUNXI_CPUCFG_BASE		0x09010000
+
+#endif /* SUNXI_MMAP_H */
diff --git a/plat/allwinner/sun50i_h616/include/sunxi_spc.h b/plat/allwinner/sun50i_h616/include/sunxi_spc.h
new file mode 100644
index 0000000..0f5965b
--- /dev/null
+++ b/plat/allwinner/sun50i_h616/include/sunxi_spc.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_SPC_H
+#define SUNXI_SPC_H
+
+#define SUNXI_SPC_NUM_PORTS		14
+
+#define SUNXI_SPC_DECPORT_STA_REG(p)	(SUNXI_SPC_BASE + 0x0000 + 0x10 * (p))
+#define SUNXI_SPC_DECPORT_SET_REG(p)	(SUNXI_SPC_BASE + 0x0004 + 0x10 * (p))
+#define SUNXI_SPC_DECPORT_CLR_REG(p)	(SUNXI_SPC_BASE + 0x0008 + 0x10 * (p))
+
+#endif /* SUNXI_SPC_H */
diff --git a/plat/allwinner/sun50i_h616/platform.mk b/plat/allwinner/sun50i_h616/platform.mk
new file mode 100644
index 0000000..1003aab
--- /dev/null
+++ b/plat/allwinner/sun50i_h616/platform.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (c) 2017-2020, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Without a management processor there is no SCPI support.
+SUNXI_PSCI_USE_SCPI	:=	0
+SUNXI_PSCI_USE_NATIVE	:=	1
+
+# The differences between the platforms are covered by the include files.
+include plat/allwinner/common/allwinner-common.mk
+
+# the above could be overwritten on the command line
+ifeq (${SUNXI_PSCI_USE_SCPI}, 1)
+    $(error "H616 does not support SCPI PSCI ops")
+endif
+
+BL31_SOURCES		+=	drivers/allwinner/axp/axp805.c		\
+				drivers/allwinner/sunxi_rsb.c
+
+$(eval $(call add_define,SUNXI_BL31_IN_DRAM))
diff --git a/plat/allwinner/sun50i_h616/sunxi_power.c b/plat/allwinner/sun50i_h616/sunxi_power.c
new file mode 100644
index 0000000..dd6ebba
--- /dev/null
+++ b/plat/allwinner/sun50i_h616/sunxi_power.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited. All rights reserved.
+ * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#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>
+
+#define AXP305_I2C_ADDR	0x36
+#define AXP305_HW_ADDR	0x745
+#define AXP305_RT_ADDR	0x3a
+
+static enum pmic_type {
+	UNKNOWN,
+	AXP305,
+} pmic;
+
+int axp_read(uint8_t reg)
+{
+	return rsb_read(AXP305_RT_ADDR, reg);
+}
+
+int axp_write(uint8_t reg, uint8_t val)
+{
+	return rsb_write(AXP305_RT_ADDR, reg, val);
+}
+
+static int rsb_init(void)
+{
+	int ret;
+
+	ret = rsb_init_controller();
+	if (ret)
+		return ret;
+
+	/* Switch to the recommended 3 MHz bus clock. */
+	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
+	if (ret)
+		return ret;
+
+	/* Initiate an I2C transaction to switch the PMIC to RSB mode. */
+	ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8);
+	if (ret)
+		return ret;
+
+	/* Associate the 8-bit runtime address with the 12-bit bus address. */
+	ret = rsb_assign_runtime_address(AXP305_HW_ADDR, AXP305_RT_ADDR);
+	if (ret)
+		return ret;
+
+	return axp_check_id();
+}
+
+int sunxi_pmic_setup(uint16_t socid, const void *fdt)
+{
+	int ret;
+
+	INFO("PMIC: Probing AXP305 on RSB\n");
+
+	ret = sunxi_init_platform_r_twi(socid, true);
+	if (ret) {
+		INFO("Could not init platform bus: %d\n", ret);
+		return ret;
+	}
+
+	ret = rsb_init();
+	if (ret) {
+		INFO("Could not init RSB: %d\n", ret);
+		return ret;
+	}
+
+	pmic = AXP305;
+	axp_setup_regulators(fdt);
+
+	/* Switch the PMIC back to I2C mode. */
+	ret = axp_write(AXP20X_MODE_REG, AXP20X_MODE_I2C);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+void sunxi_power_down(void)
+{
+	switch (pmic) {
+	case AXP305:
+		/* Re-initialise after rich OS might have used it. */
+		sunxi_init_platform_r_twi(SUNXI_SOC_H616, true);
+		rsb_init();
+		axp_power_off();
+		break;
+	default:
+		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));
+}