2 * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
4 * SPDX-License-Identifier: BSD-3-Clause
7 #include <arch_helpers.h>
9 #include <drivers/console.h>
10 #include <common/debug.h>
12 #include <drivers/arm/gicv2.h>
14 #include <plat/common/platform.h>
15 #include <platform_def.h>
16 #include <lib/psci/psci.h>
18 #include "aml_private.h"
20 #define SCPI_POWER_ON 0
21 #define SCPI_POWER_RETENTION 1
22 #define SCPI_POWER_OFF 3
24 #define SCPI_SYSTEM_SHUTDOWN 0
25 #define SCPI_SYSTEM_REBOOT 1
27 static uintptr_t gxl_sec_entrypoint
;
28 static volatile uint32_t gxl_cpu0_go
;
30 static void gxl_pm_set_reset_addr(u_register_t mpidr
, uint64_t value
)
32 unsigned int core
= plat_calc_core_pos(mpidr
);
33 uintptr_t cpu_mailbox_addr
= AML_PSCI_MAILBOX_BASE
+ (core
<< 4);
35 mmio_write_64(cpu_mailbox_addr
, value
);
38 static void gxl_pm_reset(u_register_t mpidr
)
40 unsigned int core
= plat_calc_core_pos(mpidr
);
41 uintptr_t cpu_mailbox_addr
= AML_PSCI_MAILBOX_BASE
+ (core
<< 4) + 8;
43 mmio_write_32(cpu_mailbox_addr
, 0);
46 static void __dead2
gxl_system_reset(void)
48 INFO("BL31: PSCI_SYSTEM_RESET\n");
50 u_register_t mpidr
= read_mpidr_el1();
51 uint32_t status
= mmio_read_32(AML_AO_RTI_STATUS_REG3
);
54 NOTICE("BL31: Reboot reason: 0x%x\n", status
);
60 mmio_write_32(AML_AO_RTI_STATUS_REG3
, status
);
62 ret
= aml_scpi_sys_power_state(SCPI_SYSTEM_REBOOT
);
65 ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %i\n", ret
);
73 ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n");
77 static void __dead2
gxl_system_off(void)
79 INFO("BL31: PSCI_SYSTEM_OFF\n");
81 u_register_t mpidr
= read_mpidr_el1();
84 ret
= aml_scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN
);
87 ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %i\n", ret
);
91 gxl_pm_set_reset_addr(mpidr
, 0);
96 ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n");
100 static int32_t gxl_pwr_domain_on(u_register_t mpidr
)
102 unsigned int core
= plat_calc_core_pos(mpidr
);
104 /* CPU0 can't be turned OFF, emulate it with a WFE loop */
105 if (core
== AML_PRIMARY_CPU
) {
106 VERBOSE("BL31: Releasing CPU0 from wait loop...\n");
109 flush_dcache_range((uintptr_t)&gxl_cpu0_go
,
110 sizeof(gxl_cpu0_go
));
116 return PSCI_E_SUCCESS
;
119 gxl_pm_set_reset_addr(mpidr
, gxl_sec_entrypoint
);
120 aml_scpi_set_css_power_state(mpidr
,
121 SCPI_POWER_ON
, SCPI_POWER_ON
, SCPI_POWER_ON
);
125 return PSCI_E_SUCCESS
;
128 static void gxl_pwr_domain_on_finish(const psci_power_state_t
*target_state
)
130 unsigned int core
= plat_calc_core_pos(read_mpidr_el1());
132 assert(target_state
->pwr_domain_state
[MPIDR_AFFLVL0
] ==
133 PLAT_LOCAL_STATE_OFF
);
135 if (core
== AML_PRIMARY_CPU
) {
137 flush_dcache_range((uintptr_t)&gxl_cpu0_go
,
138 sizeof(gxl_cpu0_go
));
143 gicv2_pcpu_distif_init();
144 gicv2_cpuif_enable();
147 static void gxl_pwr_domain_off(const psci_power_state_t
*target_state
)
149 u_register_t mpidr
= read_mpidr_el1();
150 unsigned int core
= plat_calc_core_pos(mpidr
);
152 gicv2_cpuif_disable();
154 /* CPU0 can't be turned OFF, emulate it with a WFE loop */
155 if (core
== AML_PRIMARY_CPU
)
158 aml_scpi_set_css_power_state(mpidr
,
159 SCPI_POWER_OFF
, SCPI_POWER_ON
, SCPI_POWER_ON
);
162 static void __dead2
gxl_pwr_domain_pwr_down_wfi(const psci_power_state_t
165 u_register_t mpidr
= read_mpidr_el1();
166 unsigned int core
= plat_calc_core_pos(mpidr
);
168 /* CPU0 can't be turned OFF, emulate it with a WFE loop */
169 if (core
== AML_PRIMARY_CPU
) {
170 VERBOSE("BL31: CPU0 entering wait loop...\n");
172 while (gxl_cpu0_go
== 0)
175 VERBOSE("BL31: CPU0 resumed.\n");
178 * Because setting CPU0's warm reset entrypoint through PSCI
179 * mailbox and/or mmio mapped RVBAR (0xda834650) does not seem
180 * to work, jump to it manually.
181 * In order to avoid an assert, mmu has to be disabled.
184 ((void(*)(void))gxl_sec_entrypoint
)();
188 gxl_pm_set_reset_addr(mpidr
, 0);
195 /*******************************************************************************
196 * Platform handlers and setup function.
197 ******************************************************************************/
198 static const plat_psci_ops_t gxl_ops
= {
199 .pwr_domain_on
= gxl_pwr_domain_on
,
200 .pwr_domain_on_finish
= gxl_pwr_domain_on_finish
,
201 .pwr_domain_off
= gxl_pwr_domain_off
,
202 .pwr_domain_pwr_down_wfi
= gxl_pwr_domain_pwr_down_wfi
,
203 .system_off
= gxl_system_off
,
204 .system_reset
= gxl_system_reset
,
207 int plat_setup_psci_ops(uintptr_t sec_entrypoint
,
208 const plat_psci_ops_t
**psci_ops
)
210 gxl_sec_entrypoint
= sec_entrypoint
;
211 *psci_ops
= &gxl_ops
;