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