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 <common/debug.h>
10 #include <drivers/arm/gicv2.h>
11 #include <drivers/console.h>
14 #include <lib/psci/psci.h>
15 #include <plat/common/platform.h>
16 #include <platform_def.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 gxbb_sec_entrypoint
;
28 static volatile uint32_t gxbb_cpu0_go
;
30 static void gxbb_program_mailbox(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
);
36 flush_dcache_range(cpu_mailbox_addr
, sizeof(uint64_t));
39 static void __dead2
gxbb_system_reset(void)
41 INFO("BL31: PSCI_SYSTEM_RESET\n");
43 uint32_t status
= mmio_read_32(AML_AO_RTI_STATUS_REG3
);
45 NOTICE("BL31: Reboot reason: 0x%x\n", status
);
51 mmio_write_32(AML_AO_RTI_STATUS_REG3
, status
);
53 int ret
= aml_scpi_sys_power_state(SCPI_SYSTEM_REBOOT
);
56 ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %u\n", ret
);
62 ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n");
66 static void __dead2
gxbb_system_off(void)
68 INFO("BL31: PSCI_SYSTEM_OFF\n");
70 unsigned int ret
= aml_scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN
);
73 ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %u\n", ret
);
77 gxbb_program_mailbox(read_mpidr_el1(), 0);
81 ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n");
85 static int32_t gxbb_pwr_domain_on(u_register_t mpidr
)
87 unsigned int core
= plat_calc_core_pos(mpidr
);
89 /* CPU0 can't be turned OFF, emulate it with a WFE loop */
90 if (core
== AML_PRIMARY_CPU
) {
91 VERBOSE("BL31: Releasing CPU0 from wait loop...\n");
94 flush_dcache_range((uintptr_t)&gxbb_cpu0_go
, sizeof(gxbb_cpu0_go
));
100 return PSCI_E_SUCCESS
;
103 gxbb_program_mailbox(mpidr
, gxbb_sec_entrypoint
);
104 aml_scpi_set_css_power_state(mpidr
,
105 SCPI_POWER_ON
, SCPI_POWER_ON
, SCPI_POWER_ON
);
109 return PSCI_E_SUCCESS
;
112 static void gxbb_pwr_domain_on_finish(const psci_power_state_t
*target_state
)
114 unsigned int core
= plat_calc_core_pos(read_mpidr_el1());
116 assert(target_state
->pwr_domain_state
[MPIDR_AFFLVL0
] ==
117 PLAT_LOCAL_STATE_OFF
);
119 if (core
== AML_PRIMARY_CPU
) {
121 flush_dcache_range((uintptr_t)&gxbb_cpu0_go
, sizeof(gxbb_cpu0_go
));
126 gicv2_pcpu_distif_init();
127 gicv2_cpuif_enable();
130 static void gxbb_pwr_domain_off(const psci_power_state_t
*target_state
)
132 u_register_t mpidr
= read_mpidr_el1();
133 unsigned int core
= plat_calc_core_pos(mpidr
);
134 uintptr_t addr
= AML_PSCI_MAILBOX_BASE
+ 8 + (core
<< 4);
136 mmio_write_32(addr
, 0xFFFFFFFF);
137 flush_dcache_range(addr
, sizeof(uint32_t));
139 gicv2_cpuif_disable();
141 /* CPU0 can't be turned OFF, emulate it with a WFE loop */
142 if (core
== AML_PRIMARY_CPU
)
145 aml_scpi_set_css_power_state(mpidr
,
146 SCPI_POWER_OFF
, SCPI_POWER_ON
, SCPI_POWER_ON
);
149 static void __dead2
gxbb_pwr_domain_pwr_down_wfi(const psci_power_state_t
152 unsigned int core
= plat_calc_core_pos(read_mpidr_el1());
154 /* CPU0 can't be turned OFF, emulate it with a WFE loop */
155 if (core
== AML_PRIMARY_CPU
) {
156 VERBOSE("BL31: CPU0 entering wait loop...\n");
158 while (gxbb_cpu0_go
== 0)
161 VERBOSE("BL31: CPU0 resumed.\n");
163 write_rmr_el3(RMR_EL3_RR_BIT
| RMR_EL3_AA64_BIT
);
172 /*******************************************************************************
173 * Platform handlers and setup function.
174 ******************************************************************************/
175 static const plat_psci_ops_t gxbb_ops
= {
176 .pwr_domain_on
= gxbb_pwr_domain_on
,
177 .pwr_domain_on_finish
= gxbb_pwr_domain_on_finish
,
178 .pwr_domain_off
= gxbb_pwr_domain_off
,
179 .pwr_domain_pwr_down_wfi
= gxbb_pwr_domain_pwr_down_wfi
,
180 .system_off
= gxbb_system_off
,
181 .system_reset
= gxbb_system_reset
,
184 int plat_setup_psci_ops(uintptr_t sec_entrypoint
,
185 const plat_psci_ops_t
**psci_ops
)
187 gxbb_sec_entrypoint
= sec_entrypoint
;
188 *psci_ops
= &gxbb_ops
;