1afd241e7SCarlo Caione /*
2afd241e7SCarlo Caione * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
3afd241e7SCarlo Caione *
4afd241e7SCarlo Caione * SPDX-License-Identifier: BSD-3-Clause
5afd241e7SCarlo Caione */
6afd241e7SCarlo Caione
7afd241e7SCarlo Caione #include <arch_helpers.h>
8afd241e7SCarlo Caione #include <assert.h>
9afd241e7SCarlo Caione #include <common/debug.h>
10afd241e7SCarlo Caione #include <drivers/arm/gicv2.h>
11afd241e7SCarlo Caione #include <drivers/console.h>
12afd241e7SCarlo Caione #include <errno.h>
13afd241e7SCarlo Caione #include <lib/mmio.h>
14afd241e7SCarlo Caione #include <lib/psci/psci.h>
15afd241e7SCarlo Caione #include <plat/common/platform.h>
16afd241e7SCarlo Caione #include <platform_def.h>
17afd241e7SCarlo Caione
18afd241e7SCarlo Caione #include "aml_private.h"
19afd241e7SCarlo Caione
20afd241e7SCarlo Caione #define SCPI_POWER_ON 0
21afd241e7SCarlo Caione #define SCPI_POWER_RETENTION 1
22afd241e7SCarlo Caione #define SCPI_POWER_OFF 3
23afd241e7SCarlo Caione
24afd241e7SCarlo Caione #define SCPI_SYSTEM_SHUTDOWN 0
25afd241e7SCarlo Caione #define SCPI_SYSTEM_REBOOT 1
26afd241e7SCarlo Caione
27afd241e7SCarlo Caione static uintptr_t axg_sec_entrypoint;
28afd241e7SCarlo Caione
axg_pm_set_reset_addr(u_register_t mpidr,uint64_t value)29afd241e7SCarlo Caione static void axg_pm_set_reset_addr(u_register_t mpidr, uint64_t value)
30afd241e7SCarlo Caione {
31afd241e7SCarlo Caione unsigned int core = plat_calc_core_pos(mpidr);
32afd241e7SCarlo Caione uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4);
33afd241e7SCarlo Caione
34afd241e7SCarlo Caione mmio_write_64(cpu_mailbox_addr, value);
35afd241e7SCarlo Caione }
36afd241e7SCarlo Caione
axg_pm_reset(u_register_t mpidr,uint32_t value)37afd241e7SCarlo Caione static void axg_pm_reset(u_register_t mpidr, uint32_t value)
38afd241e7SCarlo Caione {
39afd241e7SCarlo Caione unsigned int core = plat_calc_core_pos(mpidr);
40afd241e7SCarlo Caione uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4) + 8;
41afd241e7SCarlo Caione
42afd241e7SCarlo Caione mmio_write_32(cpu_mailbox_addr, value);
43afd241e7SCarlo Caione }
44afd241e7SCarlo Caione
axg_system_reset(void)45afd241e7SCarlo Caione static void __dead2 axg_system_reset(void)
46afd241e7SCarlo Caione {
47afd241e7SCarlo Caione u_register_t mpidr = read_mpidr_el1();
48afd241e7SCarlo Caione int ret;
49afd241e7SCarlo Caione
50afd241e7SCarlo Caione INFO("BL31: PSCI_SYSTEM_RESET\n");
51afd241e7SCarlo Caione
52afd241e7SCarlo Caione ret = aml_scpi_sys_power_state(SCPI_SYSTEM_REBOOT);
53afd241e7SCarlo Caione if (ret != 0) {
54afd241e7SCarlo Caione ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %i\n", ret);
55afd241e7SCarlo Caione panic();
56afd241e7SCarlo Caione }
57afd241e7SCarlo Caione
58afd241e7SCarlo Caione axg_pm_reset(mpidr, 0);
59afd241e7SCarlo Caione
60afd241e7SCarlo Caione wfi();
61afd241e7SCarlo Caione
62afd241e7SCarlo Caione ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n");
63afd241e7SCarlo Caione panic();
64afd241e7SCarlo Caione }
65afd241e7SCarlo Caione
axg_system_off(void)66afd241e7SCarlo Caione static void __dead2 axg_system_off(void)
67afd241e7SCarlo Caione {
68afd241e7SCarlo Caione u_register_t mpidr = read_mpidr_el1();
69afd241e7SCarlo Caione int ret;
70afd241e7SCarlo Caione
71afd241e7SCarlo Caione INFO("BL31: PSCI_SYSTEM_OFF\n");
72afd241e7SCarlo Caione
73afd241e7SCarlo Caione ret = aml_scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN);
74afd241e7SCarlo Caione if (ret != 0) {
75afd241e7SCarlo Caione ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %i\n", ret);
76afd241e7SCarlo Caione panic();
77afd241e7SCarlo Caione }
78afd241e7SCarlo Caione
79afd241e7SCarlo Caione axg_pm_set_reset_addr(mpidr, 0);
80afd241e7SCarlo Caione axg_pm_reset(mpidr, 0);
81afd241e7SCarlo Caione
82afd241e7SCarlo Caione dmbsy();
83afd241e7SCarlo Caione wfi();
84afd241e7SCarlo Caione
85afd241e7SCarlo Caione ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n");
86afd241e7SCarlo Caione panic();
87afd241e7SCarlo Caione }
88afd241e7SCarlo Caione
axg_pwr_domain_on(u_register_t mpidr)89afd241e7SCarlo Caione static int32_t axg_pwr_domain_on(u_register_t mpidr)
90afd241e7SCarlo Caione {
91afd241e7SCarlo Caione axg_pm_set_reset_addr(mpidr, axg_sec_entrypoint);
92afd241e7SCarlo Caione aml_scpi_set_css_power_state(mpidr,
93afd241e7SCarlo Caione SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON);
94afd241e7SCarlo Caione dmbsy();
95afd241e7SCarlo Caione sev();
96afd241e7SCarlo Caione
97afd241e7SCarlo Caione return PSCI_E_SUCCESS;
98afd241e7SCarlo Caione }
99afd241e7SCarlo Caione
axg_pwr_domain_on_finish(const psci_power_state_t * target_state)100afd241e7SCarlo Caione static void axg_pwr_domain_on_finish(const psci_power_state_t *target_state)
101afd241e7SCarlo Caione {
102afd241e7SCarlo Caione assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
103afd241e7SCarlo Caione PLAT_LOCAL_STATE_OFF);
104afd241e7SCarlo Caione
105afd241e7SCarlo Caione gicv2_pcpu_distif_init();
106afd241e7SCarlo Caione gicv2_cpuif_enable();
107afd241e7SCarlo Caione
108afd241e7SCarlo Caione axg_pm_set_reset_addr(read_mpidr_el1(), 0);
109afd241e7SCarlo Caione }
110afd241e7SCarlo Caione
axg_pwr_domain_off(const psci_power_state_t * target_state)111afd241e7SCarlo Caione static void axg_pwr_domain_off(const psci_power_state_t *target_state)
112afd241e7SCarlo Caione {
113afd241e7SCarlo Caione u_register_t mpidr = read_mpidr_el1();
114afd241e7SCarlo Caione uint32_t system_state = SCPI_POWER_ON;
115afd241e7SCarlo Caione uint32_t cluster_state = SCPI_POWER_ON;
116afd241e7SCarlo Caione
117afd241e7SCarlo Caione assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
118afd241e7SCarlo Caione PLAT_LOCAL_STATE_OFF);
119afd241e7SCarlo Caione
120afd241e7SCarlo Caione axg_pm_reset(mpidr, -1);
121afd241e7SCarlo Caione
122afd241e7SCarlo Caione gicv2_cpuif_disable();
123afd241e7SCarlo Caione
124afd241e7SCarlo Caione if (target_state->pwr_domain_state[MPIDR_AFFLVL2] ==
125afd241e7SCarlo Caione PLAT_LOCAL_STATE_OFF)
126afd241e7SCarlo Caione system_state = SCPI_POWER_OFF;
127afd241e7SCarlo Caione
128afd241e7SCarlo Caione if (target_state->pwr_domain_state[MPIDR_AFFLVL1] ==
129afd241e7SCarlo Caione PLAT_LOCAL_STATE_OFF)
130afd241e7SCarlo Caione cluster_state = SCPI_POWER_OFF;
131afd241e7SCarlo Caione
132afd241e7SCarlo Caione
133afd241e7SCarlo Caione aml_scpi_set_css_power_state(mpidr,
134afd241e7SCarlo Caione SCPI_POWER_OFF, cluster_state,
135afd241e7SCarlo Caione system_state);
136afd241e7SCarlo Caione }
137afd241e7SCarlo Caione
axg_pwr_domain_pwr_down_wfi(const psci_power_state_t * target_state)138afd241e7SCarlo Caione static void __dead2 axg_pwr_domain_pwr_down_wfi(const psci_power_state_t
139afd241e7SCarlo Caione *target_state)
140afd241e7SCarlo Caione {
141afd241e7SCarlo Caione dsbsy();
142afd241e7SCarlo Caione axg_pm_reset(read_mpidr_el1(), 0);
143afd241e7SCarlo Caione
144afd241e7SCarlo Caione for (;;)
145afd241e7SCarlo Caione wfi();
146afd241e7SCarlo Caione }
147afd241e7SCarlo Caione
148afd241e7SCarlo Caione /*******************************************************************************
149afd241e7SCarlo Caione * Platform handlers and setup function.
150afd241e7SCarlo Caione ******************************************************************************/
151afd241e7SCarlo Caione static const plat_psci_ops_t axg_ops = {
152afd241e7SCarlo Caione .pwr_domain_on = axg_pwr_domain_on,
153afd241e7SCarlo Caione .pwr_domain_on_finish = axg_pwr_domain_on_finish,
154afd241e7SCarlo Caione .pwr_domain_off = axg_pwr_domain_off,
155*db5fe4f4SBoyan Karatotev .pwr_domain_pwr_down = axg_pwr_domain_pwr_down_wfi,
156afd241e7SCarlo Caione .system_off = axg_system_off,
157afd241e7SCarlo Caione .system_reset = axg_system_reset
158afd241e7SCarlo Caione };
159afd241e7SCarlo Caione
plat_setup_psci_ops(uintptr_t sec_entrypoint,const plat_psci_ops_t ** psci_ops)160afd241e7SCarlo Caione int plat_setup_psci_ops(uintptr_t sec_entrypoint,
161afd241e7SCarlo Caione const plat_psci_ops_t **psci_ops)
162afd241e7SCarlo Caione {
163afd241e7SCarlo Caione axg_sec_entrypoint = sec_entrypoint;
164afd241e7SCarlo Caione *psci_ops = &axg_ops;
165afd241e7SCarlo Caione return 0;
166afd241e7SCarlo Caione }
167