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