1 /*
2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <arch_helpers.h>
8 #include <debug.h>
9 #include <mmio.h>
10 #include <psci.h>
11
12 #include "uniphier.h"
13
14 #define UNIPHIER_ROM_RSV0 0x59801200
15
16 #define UNIPHIER_SLFRSTSEL 0x61843010
17 #define UNIPHIER_SLFRSTSEL_MASK (0x3 << 0)
18 #define UNIPHIER_SLFRSTCTL 0x61843014
19 #define UNIPHIER_SLFRSTCTL_RST (1 << 0)
20
21 #define MPIDR_AFFINITY_INVALID ((u_register_t)-1)
22
23 uintptr_t uniphier_sec_entrypoint;
24
25 void uniphier_warmboot_entrypoint(void);
26 void __dead2 uniphier_fake_pwr_down(void);
27 u_register_t uniphier_holding_pen_release;
28 static int uniphier_psci_scp_mode;
29
uniphier_psci_pwr_domain_on(u_register_t mpidr)30 static int uniphier_psci_pwr_domain_on(u_register_t mpidr)
31 {
32 uniphier_holding_pen_release = mpidr;
33 flush_dcache_range((uint64_t)&uniphier_holding_pen_release,
34 sizeof(uniphier_holding_pen_release));
35
36 mmio_write_64(UNIPHIER_ROM_RSV0,
37 (uint64_t)&uniphier_warmboot_entrypoint);
38 sev();
39
40 return PSCI_E_SUCCESS;
41 }
42
uniphier_psci_pwr_domain_off(const psci_power_state_t * target_state)43 static void uniphier_psci_pwr_domain_off(const psci_power_state_t *target_state)
44 {
45 uniphier_gic_cpuif_disable();
46 }
47
uniphier_psci_pwr_domain_on_finish(const psci_power_state_t * target_state)48 static void uniphier_psci_pwr_domain_on_finish(
49 const psci_power_state_t *target_state)
50 {
51 uniphier_gic_pcpu_init();
52 uniphier_gic_cpuif_enable();
53
54 uniphier_cci_enable();
55 }
56
uniphier_psci_pwr_domain_pwr_down_wfi(const psci_power_state_t * target_state)57 static void __dead2 uniphier_psci_pwr_domain_pwr_down_wfi(
58 const psci_power_state_t *target_state)
59 {
60 /*
61 * The Boot ROM cannot distinguish warn and cold resets.
62 * Instead of the CPU reset, fake it.
63 */
64 uniphier_holding_pen_release = MPIDR_AFFINITY_INVALID;
65 flush_dcache_range((uint64_t)&uniphier_holding_pen_release,
66 sizeof(uniphier_holding_pen_release));
67
68 uniphier_fake_pwr_down();
69 }
70
uniphier_self_system_reset(void)71 static void uniphier_self_system_reset(void)
72 {
73 mmio_clrbits_32(UNIPHIER_SLFRSTSEL, UNIPHIER_SLFRSTSEL_MASK);
74 mmio_setbits_32(UNIPHIER_SLFRSTCTL, UNIPHIER_SLFRSTCTL_RST);
75 }
76
uniphier_psci_system_off(void)77 static void __dead2 uniphier_psci_system_off(void)
78 {
79 if (uniphier_psci_scp_mode) {
80 uniphier_scp_system_off();
81 } else {
82 NOTICE("SCP is disabled; can't shutdown the system.\n");
83 NOTICE("Resetting the system instead.\n");
84 uniphier_self_system_reset();
85 }
86
87 wfi();
88 ERROR("UniPhier System Off: operation not handled.\n");
89 panic();
90 }
91
uniphier_psci_system_reset(void)92 static void __dead2 uniphier_psci_system_reset(void)
93 {
94 if (uniphier_psci_scp_mode)
95 uniphier_scp_system_reset();
96 else
97 uniphier_self_system_reset();
98
99 wfi();
100 ERROR("UniPhier System Reset: operation not handled.\n");
101 panic();
102 }
103
104 static const struct plat_psci_ops uniphier_psci_ops = {
105 .pwr_domain_on = uniphier_psci_pwr_domain_on,
106 .pwr_domain_off = uniphier_psci_pwr_domain_off,
107 .pwr_domain_on_finish = uniphier_psci_pwr_domain_on_finish,
108 .pwr_domain_pwr_down_wfi = uniphier_psci_pwr_domain_pwr_down_wfi,
109 .system_off = uniphier_psci_system_off,
110 .system_reset = uniphier_psci_system_reset,
111 };
112
plat_setup_psci_ops(uintptr_t sec_entrypoint,const struct plat_psci_ops ** psci_ops)113 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
114 const struct plat_psci_ops **psci_ops)
115 {
116 uniphier_sec_entrypoint = sec_entrypoint;
117 flush_dcache_range((uint64_t)&uniphier_sec_entrypoint,
118 sizeof(uniphier_sec_entrypoint));
119
120 uniphier_psci_scp_mode = uniphier_scp_is_running();
121 flush_dcache_range((uint64_t)&uniphier_psci_scp_mode,
122 sizeof(uniphier_psci_scp_mode));
123
124 if (uniphier_psci_scp_mode)
125 uniphier_scp_open_com();
126
127 *psci_ops = &uniphier_psci_ops;
128
129 return 0;
130 }
131