• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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