blob: 3375ce71bc95c6b400ae813711ad9b7d574c89a6 [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)))
Jacky Bai48c9dcd2020-01-10 15:31:52 +080077 imx_set_cluster_powerdown(core_id, CLUSTER_PWR_STATE(target_state));
Bai Ping06e325e2018-10-28 00:12:34 +080078 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();
Jacky Bai48c9dcd2020-01-10 15:31:52 +080084 imx_anamix_override(true);
Bai Ping06e325e2018-10-28 00:12:34 +080085 }
86}
87
88void imx_domain_suspend_finish(const psci_power_state_t *target_state)
89{
90 uint64_t mpidr = read_mpidr_el1();
91 unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
92
93 /* check the system level status */
94 if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
Jacky Bai48c9dcd2020-01-10 15:31:52 +080095 imx_anamix_override(false);
Jacky Bai0d079202020-01-07 16:44:46 +080096 dram_exit_retention();
Jacky Baif7dc4012019-03-06 16:58:18 +080097 imx_set_sys_lpm(core_id, false);
Bai Ping06e325e2018-10-28 00:12:34 +080098 imx_clear_rbc_count();
99 }
100
101 /* check the cluster level power status */
102 if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
Jacky Bai48c9dcd2020-01-10 15:31:52 +0800103 imx_set_cluster_powerdown(core_id, PSCI_LOCAL_STATE_RUN);
Bai Ping06e325e2018-10-28 00:12:34 +0800104 else
105 imx_set_cluster_standby(false);
106
107 /* check the core level power status */
108 if (is_local_state_off(CORE_PWR_STATE(target_state))) {
Jacky Baia9407992020-01-08 16:56:01 +0800109 /* mark this core as awake by masking IRQ0 */
110 imx_gpc_set_a53_core_awake(core_id);
Bai Ping06e325e2018-10-28 00:12:34 +0800111 /* clear the core lpm setting */
112 imx_set_cpu_lpm(core_id, false);
113 /* enable the gic cpu interface */
114 plat_gic_cpuif_enable();
115 } else {
116 write_scr_el3(read_scr_el3() & (~0x4));
117 isb();
118 }
119}
120
121void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
122{
123 unsigned int i;
124
125 for (i = IMX_PWR_LVL0; i < PLAT_MAX_PWR_LVL; i++)
126 req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE;
127
128 req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE;
129}
130
Bai Ping06e325e2018-10-28 00:12:34 +0800131static const plat_psci_ops_t imx_plat_psci_ops = {
132 .pwr_domain_on = imx_pwr_domain_on,
133 .pwr_domain_on_finish = imx_pwr_domain_on_finish,
134 .pwr_domain_off = imx_pwr_domain_off,
135 .validate_ns_entrypoint = imx_validate_ns_entrypoint,
136 .validate_power_state = imx_validate_power_state,
137 .cpu_standby = imx_cpu_standby,
138 .pwr_domain_suspend = imx_domain_suspend,
139 .pwr_domain_suspend_finish = imx_domain_suspend_finish,
140 .pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
141 .get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
142 .system_reset = imx_system_reset,
Igor Opaniuk73999bd2021-06-03 15:00:26 +0300143 .system_reset2 = imx_system_reset2,
Bai Ping06e325e2018-10-28 00:12:34 +0800144 .system_off = imx_system_off,
145};
146
147/* export the platform specific psci ops */
148int plat_setup_psci_ops(uintptr_t sec_entrypoint,
149 const plat_psci_ops_t **psci_ops)
150{
151 imx_mailbox_init(sec_entrypoint);
152 /* sec_entrypoint is used for warm reset */
153 *psci_ops = &imx_plat_psci_ops;
154
155 return 0;
156}