aboutsummaryrefslogtreecommitdiff
path: root/plat/socionext/uniphier/uniphier_psci.c
diff options
context:
space:
mode:
Diffstat (limited to 'plat/socionext/uniphier/uniphier_psci.c')
-rw-r--r--plat/socionext/uniphier/uniphier_psci.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/plat/socionext/uniphier/uniphier_psci.c b/plat/socionext/uniphier/uniphier_psci.c
new file mode 100644
index 00000000..82081a05
--- /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;
+}