1 /*
2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdbool.h>
8
9 #include <arch.h>
10 #include <arch_helpers.h>
11 #include <common/debug.h>
12 #include <lib/mmio.h>
13 #include <lib/psci/psci.h>
14
15 #include <gpc.h>
16 #include <imx8m_psci.h>
17 #include <plat_imx8.h>
18
imx_validate_power_state(unsigned int power_state,psci_power_state_t * req_state)19 int 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
imx_domain_suspend(const psci_power_state_t * target_state)42 void 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))) {
65 imx_set_sys_lpm(core_id, true);
66 }
67 }
68
imx_domain_suspend_finish(const psci_power_state_t * target_state)69 void 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))) {
76 imx_set_sys_lpm(core_id, false);
77 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
imx_get_sys_suspend_power_state(psci_power_state_t * req_state)98 void 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
108 static 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_reset2 = imx_system_reset2,
121 .system_off = imx_system_off,
122 };
123
124 /* export the platform specific psci ops */
plat_setup_psci_ops(uintptr_t sec_entrypoint,const plat_psci_ops_t ** psci_ops)125 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
126 const plat_psci_ops_t **psci_ops)
127 {
128 imx_mailbox_init(sec_entrypoint);
129 /* sec_entrypoint is used for warm reset */
130 *psci_ops = &imx_plat_psci_ops;
131
132 return 0;
133 }
134