2 * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
4 * SPDX-License-Identifier: BSD-3-Clause
9 #include <platform_def.h>
11 #include <arch_helpers.h>
12 #include <common/debug.h>
13 #include <drivers/console.h>
15 #include <lib/psci/psci.h>
16 #include <plat/common/platform.h>
20 /* Make composite power state parameter till power level 0 */
21 #if PSCI_EXTENDED_STATE_ID
23 #define rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
24 (((lvl0_state) << PSTATE_ID_SHIFT) | \
25 ((type) << PSTATE_TYPE_SHIFT))
29 #define rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
30 (((lvl0_state) << PSTATE_ID_SHIFT) | \
31 ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \
32 ((type) << PSTATE_TYPE_SHIFT))
34 #endif /* PSCI_EXTENDED_STATE_ID */
36 #define rpi3_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \
37 (((lvl1_state) << PLAT_LOCAL_PSTATE_WIDTH) | \
38 rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type))
41 * The table storing the valid idle power states. Ensure that the
42 * array entries are populated in ascending order of state-id to
43 * enable us to use binary search during power state validation.
44 * The table must be terminated by a NULL entry.
46 static const unsigned int rpi3_pm_idle_states
[] = {
48 rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN
, PLAT_LOCAL_STATE_RET
,
49 MPIDR_AFFLVL0
, PSTATE_TYPE_STANDBY
),
51 rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN
, PLAT_LOCAL_STATE_OFF
,
52 MPIDR_AFFLVL0
, PSTATE_TYPE_POWERDOWN
),
54 rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_OFF
, PLAT_LOCAL_STATE_OFF
,
55 MPIDR_AFFLVL1
, PSTATE_TYPE_POWERDOWN
),
59 /*******************************************************************************
60 * Platform handler called to check the validity of the power state
61 * parameter. The power state parameter has to be a composite power state.
62 ******************************************************************************/
63 static int rpi3_validate_power_state(unsigned int power_state
,
64 psci_power_state_t
*req_state
)
66 unsigned int state_id
;
69 assert(req_state
!= 0);
72 * Currently we are using a linear search for finding the matching
73 * entry in the idle power state array. This can be made a binary
74 * search if the number of entries justify the additional complexity.
76 for (i
= 0; rpi3_pm_idle_states
[i
] != 0; i
++) {
77 if (power_state
== rpi3_pm_idle_states
[i
]) {
82 /* Return error if entry not found in the idle state array */
83 if (!rpi3_pm_idle_states
[i
]) {
84 return PSCI_E_INVALID_PARAMS
;
88 state_id
= psci_get_pstate_id(power_state
);
90 /* Parse the State ID and populate the state info parameter */
92 req_state
->pwr_domain_state
[i
++] = state_id
&
93 PLAT_LOCAL_PSTATE_MASK
;
94 state_id
>>= PLAT_LOCAL_PSTATE_WIDTH
;
97 return PSCI_E_SUCCESS
;
100 /*******************************************************************************
101 * Platform handler called when a CPU is about to enter standby.
102 ******************************************************************************/
103 static void rpi3_cpu_standby(plat_local_state_t cpu_state
)
105 assert(cpu_state
== PLAT_LOCAL_STATE_RET
);
108 * Enter standby state.
109 * dsb is good practice before using wfi to enter low power states
115 /*******************************************************************************
116 * Platform handler called when a power domain is about to be turned on. The
117 * mpidr determines the CPU to be turned on.
118 ******************************************************************************/
119 static int rpi3_pwr_domain_on(u_register_t mpidr
)
121 int rc
= PSCI_E_SUCCESS
;
122 unsigned int pos
= plat_core_pos_by_mpidr(mpidr
);
123 uint64_t *hold_base
= (uint64_t *)PLAT_RPI3_TM_HOLD_BASE
;
125 assert(pos
< PLATFORM_CORE_COUNT
);
127 hold_base
[pos
] = PLAT_RPI3_TM_HOLD_STATE_GO
;
129 /* Make sure that the write has completed */
138 /*******************************************************************************
139 * Platform handler called when a power domain has just been powered on after
140 * being turned off earlier. The target_state encodes the low power state that
141 * each level has woken up from.
142 ******************************************************************************/
143 void rpi3_pwr_domain_on_finish(const psci_power_state_t
*target_state
)
145 assert(target_state
->pwr_domain_state
[MPIDR_AFFLVL0
] ==
146 PLAT_LOCAL_STATE_OFF
);
149 /*******************************************************************************
150 * Platform handlers for system reset and system off.
151 ******************************************************************************/
153 /* 10 ticks (Watchdog timer = Timer clock / 16) */
154 #define RESET_TIMEOUT U(10)
156 static void __dead2
rpi3_watchdog_reset(void)
165 mmio_write_32(RPI3_PM_BASE
+ RPI3_PM_WDOG_OFFSET
,
166 RPI3_PM_PASSWORD
| RESET_TIMEOUT
);
168 rstc
= mmio_read_32(RPI3_PM_BASE
+ RPI3_PM_RSTC_OFFSET
);
169 rstc
&= ~RPI3_PM_RSTC_WRCFG_MASK
;
170 rstc
|= RPI3_PM_PASSWORD
| RPI3_PM_RSTC_WRCFG_FULL_RESET
;
171 mmio_write_32(RPI3_PM_BASE
+ RPI3_PM_RSTC_OFFSET
, rstc
);
178 static void __dead2
rpi3_system_reset(void)
180 INFO("rpi3: PSCI_SYSTEM_RESET: Invoking watchdog reset\n");
182 rpi3_watchdog_reset();
185 static void __dead2
rpi3_system_off(void)
189 INFO("rpi3: PSCI_SYSTEM_OFF: Invoking watchdog reset\n");
192 * This function doesn't actually make the Raspberry Pi turn itself off,
193 * the hardware doesn't allow it. It simply reboots it and the RSTS
194 * value tells the bootcode.bin firmware not to continue the regular
195 * bootflow and to stay in a low power mode.
198 rsts
= mmio_read_32(RPI3_PM_BASE
+ RPI3_PM_RSTS_OFFSET
);
199 rsts
|= RPI3_PM_PASSWORD
| RPI3_PM_RSTS_WRCFG_HALT
;
200 mmio_write_32(RPI3_PM_BASE
+ RPI3_PM_RSTS_OFFSET
, rsts
);
202 rpi3_watchdog_reset();
205 /*******************************************************************************
206 * Platform handlers and setup function.
207 ******************************************************************************/
208 static const plat_psci_ops_t plat_rpi3_psci_pm_ops
= {
209 .cpu_standby
= rpi3_cpu_standby
,
210 .pwr_domain_on
= rpi3_pwr_domain_on
,
211 .pwr_domain_on_finish
= rpi3_pwr_domain_on_finish
,
212 .system_off
= rpi3_system_off
,
213 .system_reset
= rpi3_system_reset
,
214 .validate_power_state
= rpi3_validate_power_state
,
217 int plat_setup_psci_ops(uintptr_t sec_entrypoint
,
218 const plat_psci_ops_t
**psci_ops
)
220 uintptr_t *entrypoint
= (void *) PLAT_RPI3_TM_ENTRYPOINT
;
222 *entrypoint
= sec_entrypoint
;
223 *psci_ops
= &plat_rpi3_psci_pm_ops
;