blob: 8b4a6d573c5c8e0f84985b3d809e3da3943feb42 [file] [log] [blame]
Bai Ping06e325e2018-10-28 00:12:34 +08001/*
Jacky Bai0d079202020-01-07 16:44:46 +08002 * Copyright (c) 2018-2023, ARM Limited and Contributors. All rights reserved.
Bai Ping06e325e2018-10-28 00:12:34 +08003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00007#include <stdbool.h>
8
Bai Ping06e325e2018-10-28 00:12:34 +08009#include <arch.h>
10#include <arch_helpers.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000011#include <common/debug.h>
Jacky Baia9407992020-01-08 16:56:01 +080012#include <drivers/delay_timer.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000013#include <lib/mmio.h>
14#include <lib/psci/psci.h>
15
Jacky Bai0d079202020-01-07 16:44:46 +080016#include <dram.h>
Bai Ping06e325e2018-10-28 00:12:34 +080017#include <gpc.h>
Jacky Baif7dc4012019-03-06 16:58:18 +080018#include <imx8m_psci.h>
Bai Ping06e325e2018-10-28 00:12:34 +080019#include <plat_imx8.h>
Bai Ping06e325e2018-10-28 00:12:34 +080020
Bai Ping06e325e2018-10-28 00:12:34 +080021int imx_validate_power_state(unsigned int power_state,
22 psci_power_state_t *req_state)
23{
24 int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
25 int pwr_type = psci_get_pstate_type(power_state);
26 int state_id = psci_get_pstate_id(power_state);
27
28 if (pwr_lvl > PLAT_MAX_PWR_LVL)
29 return PSCI_E_INVALID_PARAMS;
30
31 if (pwr_type == PSTATE_TYPE_STANDBY) {
32 CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
33 CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
34 }
35
36 if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) {
37 CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE;
38 CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
39 }
40
41 return PSCI_E_SUCCESS;
42}
43
Jacky Baia9407992020-01-08 16:56:01 +080044void imx_pwr_domain_off(const psci_power_state_t *target_state)
45{
46 uint64_t mpidr = read_mpidr_el1();
47 unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
48
49 plat_gic_cpuif_disable();
50 imx_set_cpu_pwr_off(core_id);
51
52 /*
53 * TODO: Find out why this is still
54 * needed in order not to break suspend
55 */
56 udelay(50);
57}
58
Bai Ping06e325e2018-10-28 00:12:34 +080059void imx_domain_suspend(const psci_power_state_t *target_state)
60{
Lucas Stachd36013e2022-12-08 16:44:00 +010061 uint64_t base_addr = BL31_START;
Bai Ping06e325e2018-10-28 00:12:34 +080062 uint64_t mpidr = read_mpidr_el1();
63 unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
64
65 if (is_local_state_off(CORE_PWR_STATE(target_state))) {
66 /* disable the cpu interface */
67 plat_gic_cpuif_disable();
68 imx_set_cpu_secure_entry(core_id, base_addr);
69 imx_set_cpu_lpm(core_id, true);
70 } else {
71 dsb();
72 write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
73 isb();
74 }
75
76 if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
77 imx_set_cluster_powerdown(core_id, true);
78 else
79 imx_set_cluster_standby(true);
80
81 if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
Jacky Baif7dc4012019-03-06 16:58:18 +080082 imx_set_sys_lpm(core_id, true);
Jacky Bai0d079202020-01-07 16:44:46 +080083 dram_enter_retention();
Bai Ping06e325e2018-10-28 00:12:34 +080084 }
85}
86
87void imx_domain_suspend_finish(const psci_power_state_t *target_state)
88{
89 uint64_t mpidr = read_mpidr_el1();
90 unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
91
92 /* check the system level status */
93 if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
Jacky Bai0d079202020-01-07 16:44:46 +080094 dram_exit_retention();
Jacky Baif7dc4012019-03-06 16:58:18 +080095 imx_set_sys_lpm(core_id, false);
Bai Ping06e325e2018-10-28 00:12:34 +080096 imx_clear_rbc_count();
97 }
98
99 /* check the cluster level power status */
100 if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
101 imx_set_cluster_powerdown(core_id, false);
102 else
103 imx_set_cluster_standby(false);
104
105 /* check the core level power status */
106 if (is_local_state_off(CORE_PWR_STATE(target_state))) {
Jacky Baia9407992020-01-08 16:56:01 +0800107 /* mark this core as awake by masking IRQ0 */
108 imx_gpc_set_a53_core_awake(core_id);
Bai Ping06e325e2018-10-28 00:12:34 +0800109 /* clear the core lpm setting */
110 imx_set_cpu_lpm(core_id, false);
111 /* enable the gic cpu interface */
112 plat_gic_cpuif_enable();
113 } else {
114 write_scr_el3(read_scr_el3() & (~0x4));
115 isb();
116 }
117}
118
119void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
120{
121 unsigned int i;
122
123 for (i = IMX_PWR_LVL0; i < PLAT_MAX_PWR_LVL; i++)
124 req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE;
125
126 req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE;
127}
128
Bai Ping06e325e2018-10-28 00:12:34 +0800129static const plat_psci_ops_t imx_plat_psci_ops = {
130 .pwr_domain_on = imx_pwr_domain_on,
131 .pwr_domain_on_finish = imx_pwr_domain_on_finish,
132 .pwr_domain_off = imx_pwr_domain_off,
133 .validate_ns_entrypoint = imx_validate_ns_entrypoint,
134 .validate_power_state = imx_validate_power_state,
135 .cpu_standby = imx_cpu_standby,
136 .pwr_domain_suspend = imx_domain_suspend,
137 .pwr_domain_suspend_finish = imx_domain_suspend_finish,
138 .pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
139 .get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
140 .system_reset = imx_system_reset,
Igor Opaniuk73999bd2021-06-03 15:00:26 +0300141 .system_reset2 = imx_system_reset2,
Bai Ping06e325e2018-10-28 00:12:34 +0800142 .system_off = imx_system_off,
143};
144
145/* export the platform specific psci ops */
146int plat_setup_psci_ops(uintptr_t sec_entrypoint,
147 const plat_psci_ops_t **psci_ops)
148{
149 imx_mailbox_init(sec_entrypoint);
150 /* sec_entrypoint is used for warm reset */
151 *psci_ops = &imx_plat_psci_ops;
152
153 return 0;
154}