xref: /rk3399_ARM-atf/plat/rpi/common/rpi3_pm.c (revision 4f2b984852556afc3543d90150c46be4aaadbc75)
1*4f2b9848SAndre Przywara /*
2*4f2b9848SAndre Przywara  * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
3*4f2b9848SAndre Przywara  *
4*4f2b9848SAndre Przywara  * SPDX-License-Identifier: BSD-3-Clause
5*4f2b9848SAndre Przywara  */
6*4f2b9848SAndre Przywara 
7*4f2b9848SAndre Przywara #include <assert.h>
8*4f2b9848SAndre Przywara 
9*4f2b9848SAndre Przywara #include <platform_def.h>
10*4f2b9848SAndre Przywara 
11*4f2b9848SAndre Przywara #include <arch_helpers.h>
12*4f2b9848SAndre Przywara #include <common/debug.h>
13*4f2b9848SAndre Przywara #include <drivers/console.h>
14*4f2b9848SAndre Przywara #include <lib/mmio.h>
15*4f2b9848SAndre Przywara #include <lib/psci/psci.h>
16*4f2b9848SAndre Przywara #include <plat/common/platform.h>
17*4f2b9848SAndre Przywara 
18*4f2b9848SAndre Przywara #include <rpi_hw.h>
19*4f2b9848SAndre Przywara 
20*4f2b9848SAndre Przywara /* Make composite power state parameter till power level 0 */
21*4f2b9848SAndre Przywara #if PSCI_EXTENDED_STATE_ID
22*4f2b9848SAndre Przywara 
23*4f2b9848SAndre Przywara #define rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
24*4f2b9848SAndre Przywara 		(((lvl0_state) << PSTATE_ID_SHIFT) | \
25*4f2b9848SAndre Przywara 		 ((type) << PSTATE_TYPE_SHIFT))
26*4f2b9848SAndre Przywara 
27*4f2b9848SAndre Przywara #else
28*4f2b9848SAndre Przywara 
29*4f2b9848SAndre Przywara #define rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
30*4f2b9848SAndre Przywara 		(((lvl0_state) << PSTATE_ID_SHIFT) | \
31*4f2b9848SAndre Przywara 		 ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \
32*4f2b9848SAndre Przywara 		 ((type) << PSTATE_TYPE_SHIFT))
33*4f2b9848SAndre Przywara 
34*4f2b9848SAndre Przywara #endif /* PSCI_EXTENDED_STATE_ID */
35*4f2b9848SAndre Przywara 
36*4f2b9848SAndre Przywara #define rpi3_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \
37*4f2b9848SAndre Przywara 		(((lvl1_state) << PLAT_LOCAL_PSTATE_WIDTH) | \
38*4f2b9848SAndre Przywara 		 rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type))
39*4f2b9848SAndre Przywara 
40*4f2b9848SAndre Przywara /*
41*4f2b9848SAndre Przywara  *  The table storing the valid idle power states. Ensure that the
42*4f2b9848SAndre Przywara  *  array entries are populated in ascending order of state-id to
43*4f2b9848SAndre Przywara  *  enable us to use binary search during power state validation.
44*4f2b9848SAndre Przywara  *  The table must be terminated by a NULL entry.
45*4f2b9848SAndre Przywara  */
46*4f2b9848SAndre Przywara static const unsigned int rpi3_pm_idle_states[] = {
47*4f2b9848SAndre Przywara 	/* State-id - 0x01 */
48*4f2b9848SAndre Przywara 	rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_RET,
49*4f2b9848SAndre Przywara 				MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY),
50*4f2b9848SAndre Przywara 	/* State-id - 0x02 */
51*4f2b9848SAndre Przywara 	rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_OFF,
52*4f2b9848SAndre Przywara 				MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN),
53*4f2b9848SAndre Przywara 	/* State-id - 0x22 */
54*4f2b9848SAndre Przywara 	rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_OFF, PLAT_LOCAL_STATE_OFF,
55*4f2b9848SAndre Przywara 				MPIDR_AFFLVL1, PSTATE_TYPE_POWERDOWN),
56*4f2b9848SAndre Przywara 	0,
57*4f2b9848SAndre Przywara };
58*4f2b9848SAndre Przywara 
59*4f2b9848SAndre Przywara /*******************************************************************************
60*4f2b9848SAndre Przywara  * Platform handler called to check the validity of the power state
61*4f2b9848SAndre Przywara  * parameter. The power state parameter has to be a composite power state.
62*4f2b9848SAndre Przywara  ******************************************************************************/
63*4f2b9848SAndre Przywara static int rpi3_validate_power_state(unsigned int power_state,
64*4f2b9848SAndre Przywara 				     psci_power_state_t *req_state)
65*4f2b9848SAndre Przywara {
66*4f2b9848SAndre Przywara 	unsigned int state_id;
67*4f2b9848SAndre Przywara 	int i;
68*4f2b9848SAndre Przywara 
69*4f2b9848SAndre Przywara 	assert(req_state != 0);
70*4f2b9848SAndre Przywara 
71*4f2b9848SAndre Przywara 	/*
72*4f2b9848SAndre Przywara 	 *  Currently we are using a linear search for finding the matching
73*4f2b9848SAndre Przywara 	 *  entry in the idle power state array. This can be made a binary
74*4f2b9848SAndre Przywara 	 *  search if the number of entries justify the additional complexity.
75*4f2b9848SAndre Przywara 	 */
76*4f2b9848SAndre Przywara 	for (i = 0; rpi3_pm_idle_states[i] != 0; i++) {
77*4f2b9848SAndre Przywara 		if (power_state == rpi3_pm_idle_states[i]) {
78*4f2b9848SAndre Przywara 			break;
79*4f2b9848SAndre Przywara 		}
80*4f2b9848SAndre Przywara 	}
81*4f2b9848SAndre Przywara 
82*4f2b9848SAndre Przywara 	/* Return error if entry not found in the idle state array */
83*4f2b9848SAndre Przywara 	if (!rpi3_pm_idle_states[i]) {
84*4f2b9848SAndre Przywara 		return PSCI_E_INVALID_PARAMS;
85*4f2b9848SAndre Przywara 	}
86*4f2b9848SAndre Przywara 
87*4f2b9848SAndre Przywara 	i = 0;
88*4f2b9848SAndre Przywara 	state_id = psci_get_pstate_id(power_state);
89*4f2b9848SAndre Przywara 
90*4f2b9848SAndre Przywara 	/* Parse the State ID and populate the state info parameter */
91*4f2b9848SAndre Przywara 	while (state_id) {
92*4f2b9848SAndre Przywara 		req_state->pwr_domain_state[i++] = state_id &
93*4f2b9848SAndre Przywara 						PLAT_LOCAL_PSTATE_MASK;
94*4f2b9848SAndre Przywara 		state_id >>= PLAT_LOCAL_PSTATE_WIDTH;
95*4f2b9848SAndre Przywara 	}
96*4f2b9848SAndre Przywara 
97*4f2b9848SAndre Przywara 	return PSCI_E_SUCCESS;
98*4f2b9848SAndre Przywara }
99*4f2b9848SAndre Przywara 
100*4f2b9848SAndre Przywara /*******************************************************************************
101*4f2b9848SAndre Przywara  * Platform handler called when a CPU is about to enter standby.
102*4f2b9848SAndre Przywara  ******************************************************************************/
103*4f2b9848SAndre Przywara static void rpi3_cpu_standby(plat_local_state_t cpu_state)
104*4f2b9848SAndre Przywara {
105*4f2b9848SAndre Przywara 	assert(cpu_state == PLAT_LOCAL_STATE_RET);
106*4f2b9848SAndre Przywara 
107*4f2b9848SAndre Przywara 	/*
108*4f2b9848SAndre Przywara 	 * Enter standby state.
109*4f2b9848SAndre Przywara 	 * dsb is good practice before using wfi to enter low power states
110*4f2b9848SAndre Przywara 	 */
111*4f2b9848SAndre Przywara 	dsb();
112*4f2b9848SAndre Przywara 	wfi();
113*4f2b9848SAndre Przywara }
114*4f2b9848SAndre Przywara 
115*4f2b9848SAndre Przywara /*******************************************************************************
116*4f2b9848SAndre Przywara  * Platform handler called when a power domain is about to be turned on. The
117*4f2b9848SAndre Przywara  * mpidr determines the CPU to be turned on.
118*4f2b9848SAndre Przywara  ******************************************************************************/
119*4f2b9848SAndre Przywara static int rpi3_pwr_domain_on(u_register_t mpidr)
120*4f2b9848SAndre Przywara {
121*4f2b9848SAndre Przywara 	int rc = PSCI_E_SUCCESS;
122*4f2b9848SAndre Przywara 	unsigned int pos = plat_core_pos_by_mpidr(mpidr);
123*4f2b9848SAndre Przywara 	uint64_t *hold_base = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE;
124*4f2b9848SAndre Przywara 
125*4f2b9848SAndre Przywara 	assert(pos < PLATFORM_CORE_COUNT);
126*4f2b9848SAndre Przywara 
127*4f2b9848SAndre Przywara 	hold_base[pos] = PLAT_RPI3_TM_HOLD_STATE_GO;
128*4f2b9848SAndre Przywara 
129*4f2b9848SAndre Przywara 	/* Make sure that the write has completed */
130*4f2b9848SAndre Przywara 	dsb();
131*4f2b9848SAndre Przywara 	isb();
132*4f2b9848SAndre Przywara 
133*4f2b9848SAndre Przywara 	sev();
134*4f2b9848SAndre Przywara 
135*4f2b9848SAndre Przywara 	return rc;
136*4f2b9848SAndre Przywara }
137*4f2b9848SAndre Przywara 
138*4f2b9848SAndre Przywara /*******************************************************************************
139*4f2b9848SAndre Przywara  * Platform handler called when a power domain has just been powered on after
140*4f2b9848SAndre Przywara  * being turned off earlier. The target_state encodes the low power state that
141*4f2b9848SAndre Przywara  * each level has woken up from.
142*4f2b9848SAndre Przywara  ******************************************************************************/
143*4f2b9848SAndre Przywara static void rpi3_pwr_domain_on_finish(const psci_power_state_t *target_state)
144*4f2b9848SAndre Przywara {
145*4f2b9848SAndre Przywara 	assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
146*4f2b9848SAndre Przywara 					PLAT_LOCAL_STATE_OFF);
147*4f2b9848SAndre Przywara }
148*4f2b9848SAndre Przywara 
149*4f2b9848SAndre Przywara /*******************************************************************************
150*4f2b9848SAndre Przywara  * Platform handlers for system reset and system off.
151*4f2b9848SAndre Przywara  ******************************************************************************/
152*4f2b9848SAndre Przywara 
153*4f2b9848SAndre Przywara /* 10 ticks (Watchdog timer = Timer clock / 16) */
154*4f2b9848SAndre Przywara #define RESET_TIMEOUT	U(10)
155*4f2b9848SAndre Przywara 
156*4f2b9848SAndre Przywara static void __dead2 rpi3_watchdog_reset(void)
157*4f2b9848SAndre Przywara {
158*4f2b9848SAndre Przywara 	uint32_t rstc;
159*4f2b9848SAndre Przywara 
160*4f2b9848SAndre Przywara 	console_flush();
161*4f2b9848SAndre Przywara 
162*4f2b9848SAndre Przywara 	dsbsy();
163*4f2b9848SAndre Przywara 	isb();
164*4f2b9848SAndre Przywara 
165*4f2b9848SAndre Przywara 	mmio_write_32(RPI3_PM_BASE + RPI3_PM_WDOG_OFFSET,
166*4f2b9848SAndre Przywara 		      RPI3_PM_PASSWORD | RESET_TIMEOUT);
167*4f2b9848SAndre Przywara 
168*4f2b9848SAndre Przywara 	rstc = mmio_read_32(RPI3_PM_BASE + RPI3_PM_RSTC_OFFSET);
169*4f2b9848SAndre Przywara 	rstc &= ~RPI3_PM_RSTC_WRCFG_MASK;
170*4f2b9848SAndre Przywara 	rstc |= RPI3_PM_PASSWORD | RPI3_PM_RSTC_WRCFG_FULL_RESET;
171*4f2b9848SAndre Przywara 	mmio_write_32(RPI3_PM_BASE + RPI3_PM_RSTC_OFFSET, rstc);
172*4f2b9848SAndre Przywara 
173*4f2b9848SAndre Przywara 	for (;;) {
174*4f2b9848SAndre Przywara 		wfi();
175*4f2b9848SAndre Przywara 	}
176*4f2b9848SAndre Przywara }
177*4f2b9848SAndre Przywara 
178*4f2b9848SAndre Przywara static void __dead2 rpi3_system_reset(void)
179*4f2b9848SAndre Przywara {
180*4f2b9848SAndre Przywara 	INFO("rpi3: PSCI_SYSTEM_RESET: Invoking watchdog reset\n");
181*4f2b9848SAndre Przywara 
182*4f2b9848SAndre Przywara 	rpi3_watchdog_reset();
183*4f2b9848SAndre Przywara }
184*4f2b9848SAndre Przywara 
185*4f2b9848SAndre Przywara static void __dead2 rpi3_system_off(void)
186*4f2b9848SAndre Przywara {
187*4f2b9848SAndre Przywara 	uint32_t rsts;
188*4f2b9848SAndre Przywara 
189*4f2b9848SAndre Przywara 	INFO("rpi3: PSCI_SYSTEM_OFF: Invoking watchdog reset\n");
190*4f2b9848SAndre Przywara 
191*4f2b9848SAndre Przywara 	/*
192*4f2b9848SAndre Przywara 	 * This function doesn't actually make the Raspberry Pi turn itself off,
193*4f2b9848SAndre Przywara 	 * the hardware doesn't allow it. It simply reboots it and the RSTS
194*4f2b9848SAndre Przywara 	 * value tells the bootcode.bin firmware not to continue the regular
195*4f2b9848SAndre Przywara 	 * bootflow and to stay in a low power mode.
196*4f2b9848SAndre Przywara 	 */
197*4f2b9848SAndre Przywara 
198*4f2b9848SAndre Przywara 	rsts = mmio_read_32(RPI3_PM_BASE + RPI3_PM_RSTS_OFFSET);
199*4f2b9848SAndre Przywara 	rsts |= RPI3_PM_PASSWORD | RPI3_PM_RSTS_WRCFG_HALT;
200*4f2b9848SAndre Przywara 	mmio_write_32(RPI3_PM_BASE + RPI3_PM_RSTS_OFFSET, rsts);
201*4f2b9848SAndre Przywara 
202*4f2b9848SAndre Przywara 	rpi3_watchdog_reset();
203*4f2b9848SAndre Przywara }
204*4f2b9848SAndre Przywara 
205*4f2b9848SAndre Przywara /*******************************************************************************
206*4f2b9848SAndre Przywara  * Platform handlers and setup function.
207*4f2b9848SAndre Przywara  ******************************************************************************/
208*4f2b9848SAndre Przywara static const plat_psci_ops_t plat_rpi3_psci_pm_ops = {
209*4f2b9848SAndre Przywara 	.cpu_standby = rpi3_cpu_standby,
210*4f2b9848SAndre Przywara 	.pwr_domain_on = rpi3_pwr_domain_on,
211*4f2b9848SAndre Przywara 	.pwr_domain_on_finish = rpi3_pwr_domain_on_finish,
212*4f2b9848SAndre Przywara 	.system_off = rpi3_system_off,
213*4f2b9848SAndre Przywara 	.system_reset = rpi3_system_reset,
214*4f2b9848SAndre Przywara 	.validate_power_state = rpi3_validate_power_state,
215*4f2b9848SAndre Przywara };
216*4f2b9848SAndre Przywara 
217*4f2b9848SAndre Przywara int plat_setup_psci_ops(uintptr_t sec_entrypoint,
218*4f2b9848SAndre Przywara 			const plat_psci_ops_t **psci_ops)
219*4f2b9848SAndre Przywara {
220*4f2b9848SAndre Przywara 	uintptr_t *entrypoint = (void *) PLAT_RPI3_TM_ENTRYPOINT;
221*4f2b9848SAndre Przywara 
222*4f2b9848SAndre Przywara 	*entrypoint = sec_entrypoint;
223*4f2b9848SAndre Przywara 	*psci_ops = &plat_rpi3_psci_pm_ops;
224*4f2b9848SAndre Przywara 
225*4f2b9848SAndre Przywara 	return 0;
226*4f2b9848SAndre Przywara }
227