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