blob: 04e191ff89aae5fc8caf0b4fc582b4504632ea98 [file] [log] [blame]
Bai Ping06e325e2018-10-28 00:12:34 +08001/*
2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3 *
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>
12#include <lib/mmio.h>
13#include <lib/psci/psci.h>
14
Bai Ping06e325e2018-10-28 00:12:34 +080015#include <gpc.h>
Jacky Baif7dc4012019-03-06 16:58:18 +080016#include <imx8m_psci.h>
Bai Ping06e325e2018-10-28 00:12:34 +080017#include <plat_imx8.h>
Bai Ping06e325e2018-10-28 00:12:34 +080018
Bai Ping06e325e2018-10-28 00:12:34 +080019int imx_validate_power_state(unsigned int power_state,
20 psci_power_state_t *req_state)
21{
22 int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
23 int pwr_type = psci_get_pstate_type(power_state);
24 int state_id = psci_get_pstate_id(power_state);
25
26 if (pwr_lvl > PLAT_MAX_PWR_LVL)
27 return PSCI_E_INVALID_PARAMS;
28
29 if (pwr_type == PSTATE_TYPE_STANDBY) {
30 CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
31 CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
32 }
33
34 if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) {
35 CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE;
36 CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
37 }
38
39 return PSCI_E_SUCCESS;
40}
41
Bai Ping06e325e2018-10-28 00:12:34 +080042void imx_domain_suspend(const psci_power_state_t *target_state)
43{
44 uint64_t base_addr = BL31_BASE;
45 uint64_t mpidr = read_mpidr_el1();
46 unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
47
48 if (is_local_state_off(CORE_PWR_STATE(target_state))) {
49 /* disable the cpu interface */
50 plat_gic_cpuif_disable();
51 imx_set_cpu_secure_entry(core_id, base_addr);
52 imx_set_cpu_lpm(core_id, true);
53 } else {
54 dsb();
55 write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
56 isb();
57 }
58
59 if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
60 imx_set_cluster_powerdown(core_id, true);
61 else
62 imx_set_cluster_standby(true);
63
64 if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
Jacky Baif7dc4012019-03-06 16:58:18 +080065 imx_set_sys_lpm(core_id, true);
Bai Ping06e325e2018-10-28 00:12:34 +080066 }
67}
68
69void imx_domain_suspend_finish(const psci_power_state_t *target_state)
70{
71 uint64_t mpidr = read_mpidr_el1();
72 unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
73
74 /* check the system level status */
75 if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
Jacky Baif7dc4012019-03-06 16:58:18 +080076 imx_set_sys_lpm(core_id, false);
Bai Ping06e325e2018-10-28 00:12:34 +080077 imx_clear_rbc_count();
78 }
79
80 /* check the cluster level power status */
81 if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
82 imx_set_cluster_powerdown(core_id, false);
83 else
84 imx_set_cluster_standby(false);
85
86 /* check the core level power status */
87 if (is_local_state_off(CORE_PWR_STATE(target_state))) {
88 /* clear the core lpm setting */
89 imx_set_cpu_lpm(core_id, false);
90 /* enable the gic cpu interface */
91 plat_gic_cpuif_enable();
92 } else {
93 write_scr_el3(read_scr_el3() & (~0x4));
94 isb();
95 }
96}
97
98void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
99{
100 unsigned int i;
101
102 for (i = IMX_PWR_LVL0; i < PLAT_MAX_PWR_LVL; i++)
103 req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE;
104
105 req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE;
106}
107
Bai Ping06e325e2018-10-28 00:12:34 +0800108static const plat_psci_ops_t imx_plat_psci_ops = {
109 .pwr_domain_on = imx_pwr_domain_on,
110 .pwr_domain_on_finish = imx_pwr_domain_on_finish,
111 .pwr_domain_off = imx_pwr_domain_off,
112 .validate_ns_entrypoint = imx_validate_ns_entrypoint,
113 .validate_power_state = imx_validate_power_state,
114 .cpu_standby = imx_cpu_standby,
115 .pwr_domain_suspend = imx_domain_suspend,
116 .pwr_domain_suspend_finish = imx_domain_suspend_finish,
117 .pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
118 .get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
119 .system_reset = imx_system_reset,
120 .system_off = imx_system_off,
121};
122
123/* export the platform specific psci ops */
124int plat_setup_psci_ops(uintptr_t sec_entrypoint,
125 const plat_psci_ops_t **psci_ops)
126{
127 imx_mailbox_init(sec_entrypoint);
128 /* sec_entrypoint is used for warm reset */
129 *psci_ops = &imx_plat_psci_ops;
130
131 return 0;
132}