uniphier: support Socionext UniPhier platform

Initial commit for Socionext UniPhier SoC support.  BL1, Bl2, and
BL31 are supported.  Refer to docs/plat/socionext-uniphier.md for
more detais.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
diff --git a/plat/socionext/uniphier/uniphier_psci.c b/plat/socionext/uniphier/uniphier_psci.c
new file mode 100644
index 0000000..82081a0
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_psci.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <debug.h>
+#include <mmio.h>
+#include <psci.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_ROM_RSV0		0x59801200
+
+#define UNIPHIER_SLFRSTSEL		0x61843010
+#define   UNIPHIER_SLFRSTSEL_MASK		(0x3 << 0)
+#define UNIPHIER_SLFRSTCTL		0x61843014
+#define   UNIPHIER_SLFRSTCTL_RST		(1 << 0)
+
+#define MPIDR_AFFINITY_INVALID		((u_register_t)-1)
+
+uintptr_t uniphier_sec_entrypoint;
+
+void uniphier_warmboot_entrypoint(void);
+void __dead2 uniphier_fake_pwr_down(void);
+u_register_t uniphier_holding_pen_release;
+static int uniphier_psci_scp_mode;
+
+static int uniphier_psci_pwr_domain_on(u_register_t mpidr)
+{
+	uniphier_holding_pen_release = mpidr;
+	flush_dcache_range((uint64_t)&uniphier_holding_pen_release,
+			   sizeof(uniphier_holding_pen_release));
+
+	mmio_write_64(UNIPHIER_ROM_RSV0,
+		      (uint64_t)&uniphier_warmboot_entrypoint);
+	sev();
+
+	return PSCI_E_SUCCESS;
+}
+
+static void uniphier_psci_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	uniphier_gic_cpuif_disable();
+}
+
+static void uniphier_psci_pwr_domain_on_finish(
+					const psci_power_state_t *target_state)
+{
+	uniphier_gic_pcpu_init();
+	uniphier_gic_cpuif_enable();
+
+	uniphier_cci_enable();
+}
+
+static void __dead2 uniphier_psci_pwr_domain_pwr_down_wfi(
+					const psci_power_state_t *target_state)
+{
+	/*
+	 * The Boot ROM cannot distinguish warn and cold resets.
+	 * Instead of the CPU reset, fake it.
+	 */
+	uniphier_holding_pen_release = MPIDR_AFFINITY_INVALID;
+	flush_dcache_range((uint64_t)&uniphier_holding_pen_release,
+			   sizeof(uniphier_holding_pen_release));
+
+	uniphier_fake_pwr_down();
+}
+
+static void uniphier_self_system_reset(void)
+{
+	mmio_clrbits_32(UNIPHIER_SLFRSTSEL, UNIPHIER_SLFRSTSEL_MASK);
+	mmio_setbits_32(UNIPHIER_SLFRSTCTL, UNIPHIER_SLFRSTCTL_RST);
+}
+
+static void __dead2 uniphier_psci_system_off(void)
+{
+	if (uniphier_psci_scp_mode) {
+		uniphier_scp_system_off();
+	} else {
+		NOTICE("SCP is disabled; can't shutdown the system.\n");
+		NOTICE("Resetting the system instead.\n");
+		uniphier_self_system_reset();
+	}
+
+	wfi();
+	ERROR("UniPhier System Off: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 uniphier_psci_system_reset(void)
+{
+	if (uniphier_psci_scp_mode)
+		uniphier_scp_system_reset();
+	else
+		uniphier_self_system_reset();
+
+	wfi();
+	ERROR("UniPhier System Reset: operation not handled.\n");
+	panic();
+}
+
+static const struct plat_psci_ops uniphier_psci_ops = {
+	.pwr_domain_on = uniphier_psci_pwr_domain_on,
+	.pwr_domain_off = uniphier_psci_pwr_domain_off,
+	.pwr_domain_on_finish = uniphier_psci_pwr_domain_on_finish,
+	.pwr_domain_pwr_down_wfi = uniphier_psci_pwr_domain_pwr_down_wfi,
+	.system_off = uniphier_psci_system_off,
+	.system_reset = uniphier_psci_system_reset,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const struct plat_psci_ops **psci_ops)
+{
+	uniphier_sec_entrypoint = sec_entrypoint;
+	flush_dcache_range((uint64_t)&uniphier_sec_entrypoint,
+			   sizeof(uniphier_sec_entrypoint));
+
+	uniphier_psci_scp_mode = uniphier_scp_is_running();
+	flush_dcache_range((uint64_t)&uniphier_psci_scp_mode,
+			   sizeof(uniphier_psci_scp_mode));
+
+	if (uniphier_psci_scp_mode)
+		uniphier_scp_open_com();
+
+	*psci_ops = &uniphier_psci_ops;
+
+	return 0;
+}