xref: /arm-trusted-firmware/plat/brcm/board/stingray/src/brcm_pm_ops.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2017 - 2020, Broadcom
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <errno.h>
9*91f16700Schasinglulu #include <inttypes.h>
10*91f16700Schasinglulu 
11*91f16700Schasinglulu #include <arch_helpers.h>
12*91f16700Schasinglulu #include <common/debug.h>
13*91f16700Schasinglulu #include <drivers/arm/ccn.h>
14*91f16700Schasinglulu #include <lib/bakery_lock.h>
15*91f16700Schasinglulu #include <lib/mmio.h>
16*91f16700Schasinglulu #include <lib/psci/psci.h>
17*91f16700Schasinglulu #include <lib/spinlock.h>
18*91f16700Schasinglulu 
19*91f16700Schasinglulu #include <brcm_scpi.h>
20*91f16700Schasinglulu #include <chimp.h>
21*91f16700Schasinglulu #include <cmn_plat_util.h>
22*91f16700Schasinglulu #include <plat_brcm.h>
23*91f16700Schasinglulu #include <platform_def.h>
24*91f16700Schasinglulu #include <sr_utils.h>
25*91f16700Schasinglulu 
26*91f16700Schasinglulu #include "m0_cfg.h"
27*91f16700Schasinglulu 
28*91f16700Schasinglulu 
29*91f16700Schasinglulu #define CORE_PWR_STATE(state)	((state)->pwr_domain_state[MPIDR_AFFLVL0])
30*91f16700Schasinglulu #define CLUSTER_PWR_STATE(state)	\
31*91f16700Schasinglulu 			((state)->pwr_domain_state[MPIDR_AFFLVL1])
32*91f16700Schasinglulu #define SYSTEM_PWR_STATE(state)	((state)->pwr_domain_state[MPIDR_AFFLVL2])
33*91f16700Schasinglulu 
34*91f16700Schasinglulu #define VENDOR_RST_TYPE_SHIFT	4
35*91f16700Schasinglulu 
36*91f16700Schasinglulu #if HW_ASSISTED_COHERENCY
37*91f16700Schasinglulu /*
38*91f16700Schasinglulu  * On systems where participant CPUs are cache-coherent, we can use spinlocks
39*91f16700Schasinglulu  * instead of bakery locks.
40*91f16700Schasinglulu  */
41*91f16700Schasinglulu spinlock_t event_lock;
42*91f16700Schasinglulu #define event_lock_get(_lock) spin_lock(&_lock)
43*91f16700Schasinglulu #define event_lock_release(_lock) spin_unlock(&_lock)
44*91f16700Schasinglulu 
45*91f16700Schasinglulu #else
46*91f16700Schasinglulu /*
47*91f16700Schasinglulu  * Use bakery locks for state coordination as not all participants are
48*91f16700Schasinglulu  * cache coherent now.
49*91f16700Schasinglulu  */
50*91f16700Schasinglulu DEFINE_BAKERY_LOCK(event_lock);
51*91f16700Schasinglulu #define event_lock_get(_lock) bakery_lock_get(&_lock)
52*91f16700Schasinglulu #define event_lock_release(_lock) bakery_lock_release(&_lock)
53*91f16700Schasinglulu #endif
54*91f16700Schasinglulu 
55*91f16700Schasinglulu static int brcm_pwr_domain_on(u_register_t mpidr)
56*91f16700Schasinglulu {
57*91f16700Schasinglulu 	/*
58*91f16700Schasinglulu 	 * SCP takes care of powering up parent power domains so we
59*91f16700Schasinglulu 	 * only need to care about level 0
60*91f16700Schasinglulu 	 */
61*91f16700Schasinglulu 	scpi_set_brcm_power_state(mpidr, scpi_power_on, scpi_power_on,
62*91f16700Schasinglulu 				  scpi_power_on);
63*91f16700Schasinglulu 
64*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
65*91f16700Schasinglulu }
66*91f16700Schasinglulu 
67*91f16700Schasinglulu /*******************************************************************************
68*91f16700Schasinglulu  * Handler called when a power level has just been powered on after
69*91f16700Schasinglulu  * being turned off earlier. The target_state encodes the low power state that
70*91f16700Schasinglulu  * each level has woken up from. This handler would never be invoked with
71*91f16700Schasinglulu  * the system power domain uninitialized as either the primary would have taken
72*91f16700Schasinglulu  * care of it as part of cold boot or the first core awakened from system
73*91f16700Schasinglulu  * suspend would have already initialized it.
74*91f16700Schasinglulu  ******************************************************************************/
75*91f16700Schasinglulu static void brcm_pwr_domain_on_finish(const psci_power_state_t *target_state)
76*91f16700Schasinglulu {
77*91f16700Schasinglulu 	unsigned long cluster_id = MPIDR_AFFLVL1_VAL(read_mpidr());
78*91f16700Schasinglulu 
79*91f16700Schasinglulu 	/* Assert that the system power domain need not be initialized */
80*91f16700Schasinglulu 	assert(SYSTEM_PWR_STATE(target_state) == PLAT_LOCAL_STATE_RUN);
81*91f16700Schasinglulu 
82*91f16700Schasinglulu 	assert(CORE_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF);
83*91f16700Schasinglulu 
84*91f16700Schasinglulu 	/*
85*91f16700Schasinglulu 	 * Perform the common cluster specific operations i.e enable coherency
86*91f16700Schasinglulu 	 * if this cluster was off.
87*91f16700Schasinglulu 	 */
88*91f16700Schasinglulu 	if (CLUSTER_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF) {
89*91f16700Schasinglulu 		INFO("Cluster #%lu entering to snoop/dvm domain\n", cluster_id);
90*91f16700Schasinglulu 		ccn_enter_snoop_dvm_domain(1 << cluster_id);
91*91f16700Schasinglulu 	}
92*91f16700Schasinglulu 
93*91f16700Schasinglulu 	/* Program the gic per-cpu distributor or re-distributor interface */
94*91f16700Schasinglulu 	plat_brcm_gic_pcpu_init();
95*91f16700Schasinglulu 
96*91f16700Schasinglulu 	/* Enable the gic cpu interface */
97*91f16700Schasinglulu 	plat_brcm_gic_cpuif_enable();
98*91f16700Schasinglulu }
99*91f16700Schasinglulu 
100*91f16700Schasinglulu static void brcm_power_down_common(void)
101*91f16700Schasinglulu {
102*91f16700Schasinglulu 	unsigned int standbywfil2, standbywfi;
103*91f16700Schasinglulu 	uint64_t mpidr = read_mpidr_el1();
104*91f16700Schasinglulu 
105*91f16700Schasinglulu 	switch (MPIDR_AFFLVL1_VAL(mpidr)) {
106*91f16700Schasinglulu 	case 0x0:
107*91f16700Schasinglulu 		standbywfi = CDRU_PROC_EVENT_CLEAR__IH0_CDRU_STANDBYWFI;
108*91f16700Schasinglulu 		standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH0_CDRU_STANDBYWFIL2;
109*91f16700Schasinglulu 		break;
110*91f16700Schasinglulu 	case 0x1:
111*91f16700Schasinglulu 		standbywfi = CDRU_PROC_EVENT_CLEAR__IH1_CDRU_STANDBYWFI;
112*91f16700Schasinglulu 		standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH1_CDRU_STANDBYWFIL2;
113*91f16700Schasinglulu 		break;
114*91f16700Schasinglulu 	case 0x2:
115*91f16700Schasinglulu 		standbywfi = CDRU_PROC_EVENT_CLEAR__IH2_CDRU_STANDBYWFI;
116*91f16700Schasinglulu 		standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH2_CDRU_STANDBYWFIL2;
117*91f16700Schasinglulu 		break;
118*91f16700Schasinglulu 	case 0x3:
119*91f16700Schasinglulu 		standbywfi = CDRU_PROC_EVENT_CLEAR__IH3_CDRU_STANDBYWFI;
120*91f16700Schasinglulu 		standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH3_CDRU_STANDBYWFIL2;
121*91f16700Schasinglulu 		break;
122*91f16700Schasinglulu 	default:
123*91f16700Schasinglulu 		ERROR("Invalid cluster #%" PRIx64 "\n", MPIDR_AFFLVL1_VAL(mpidr));
124*91f16700Schasinglulu 		return;
125*91f16700Schasinglulu 	}
126*91f16700Schasinglulu 	/* Clear the WFI status bit */
127*91f16700Schasinglulu 	event_lock_get(event_lock);
128*91f16700Schasinglulu 	mmio_setbits_32(CDRU_PROC_EVENT_CLEAR,
129*91f16700Schasinglulu 			(1 << (standbywfi + MPIDR_AFFLVL0_VAL(mpidr))) |
130*91f16700Schasinglulu 			(1 << standbywfil2));
131*91f16700Schasinglulu 	event_lock_release(event_lock);
132*91f16700Schasinglulu }
133*91f16700Schasinglulu 
134*91f16700Schasinglulu /*
135*91f16700Schasinglulu  * Helper function to inform power down state to SCP.
136*91f16700Schasinglulu  */
137*91f16700Schasinglulu static void brcm_scp_suspend(const psci_power_state_t *target_state)
138*91f16700Schasinglulu {
139*91f16700Schasinglulu 	uint32_t cluster_state = scpi_power_on;
140*91f16700Schasinglulu 	uint32_t system_state = scpi_power_on;
141*91f16700Schasinglulu 
142*91f16700Schasinglulu 	/* Check if power down at system power domain level is requested */
143*91f16700Schasinglulu 	if (SYSTEM_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF)
144*91f16700Schasinglulu 		system_state = scpi_power_retention;
145*91f16700Schasinglulu 
146*91f16700Schasinglulu 	/* Check if Cluster is to be turned off */
147*91f16700Schasinglulu 	if (CLUSTER_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF)
148*91f16700Schasinglulu 		cluster_state = scpi_power_off;
149*91f16700Schasinglulu 
150*91f16700Schasinglulu 	/*
151*91f16700Schasinglulu 	 * Ask the SCP to power down the appropriate components depending upon
152*91f16700Schasinglulu 	 * their state.
153*91f16700Schasinglulu 	 */
154*91f16700Schasinglulu 	scpi_set_brcm_power_state(read_mpidr_el1(),
155*91f16700Schasinglulu 				  scpi_power_off,
156*91f16700Schasinglulu 				  cluster_state,
157*91f16700Schasinglulu 				  system_state);
158*91f16700Schasinglulu }
159*91f16700Schasinglulu 
160*91f16700Schasinglulu /*
161*91f16700Schasinglulu  * Helper function to turn off a CPU power domain and its parent power domains
162*91f16700Schasinglulu  * if applicable. Since SCPI doesn't differentiate between OFF and suspend, we
163*91f16700Schasinglulu  * call the suspend helper here.
164*91f16700Schasinglulu  */
165*91f16700Schasinglulu static void brcm_scp_off(const psci_power_state_t *target_state)
166*91f16700Schasinglulu {
167*91f16700Schasinglulu 	brcm_scp_suspend(target_state);
168*91f16700Schasinglulu }
169*91f16700Schasinglulu 
170*91f16700Schasinglulu static void brcm_pwr_domain_off(const psci_power_state_t *target_state)
171*91f16700Schasinglulu {
172*91f16700Schasinglulu 	unsigned long cluster_id = MPIDR_AFFLVL1_VAL(read_mpidr_el1());
173*91f16700Schasinglulu 
174*91f16700Schasinglulu 	assert(CORE_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF);
175*91f16700Schasinglulu 	/* Prevent interrupts from spuriously waking up this cpu */
176*91f16700Schasinglulu 	plat_brcm_gic_cpuif_disable();
177*91f16700Schasinglulu 
178*91f16700Schasinglulu 	/* Turn redistributor off */
179*91f16700Schasinglulu 	plat_brcm_gic_redistif_off();
180*91f16700Schasinglulu 
181*91f16700Schasinglulu 	/* If Cluster is to be turned off, disable coherency */
182*91f16700Schasinglulu 	if (CLUSTER_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF)
183*91f16700Schasinglulu 		ccn_exit_snoop_dvm_domain(1 << cluster_id);
184*91f16700Schasinglulu 
185*91f16700Schasinglulu 	brcm_power_down_common();
186*91f16700Schasinglulu 
187*91f16700Schasinglulu 	brcm_scp_off(target_state);
188*91f16700Schasinglulu }
189*91f16700Schasinglulu 
190*91f16700Schasinglulu /*******************************************************************************
191*91f16700Schasinglulu  * Handler called when the CPU power domain is about to enter standby.
192*91f16700Schasinglulu  ******************************************************************************/
193*91f16700Schasinglulu static void brcm_cpu_standby(plat_local_state_t cpu_state)
194*91f16700Schasinglulu {
195*91f16700Schasinglulu 	unsigned int scr;
196*91f16700Schasinglulu 
197*91f16700Schasinglulu 	assert(cpu_state == PLAT_LOCAL_STATE_RET);
198*91f16700Schasinglulu 
199*91f16700Schasinglulu 	scr = read_scr_el3();
200*91f16700Schasinglulu 	/*
201*91f16700Schasinglulu 	 * Enable the Non secure interrupt to wake the CPU.
202*91f16700Schasinglulu 	 * In GICv3 affinity routing mode, the non secure group1 interrupts use
203*91f16700Schasinglulu 	 * the PhysicalFIQ at EL3 whereas in GICv2, it uses the PhysicalIRQ.
204*91f16700Schasinglulu 	 * Enabling both the bits works for both GICv2 mode and GICv3 affinity
205*91f16700Schasinglulu 	 * routing mode.
206*91f16700Schasinglulu 	 */
207*91f16700Schasinglulu 	write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
208*91f16700Schasinglulu 	isb();
209*91f16700Schasinglulu 	dsb();
210*91f16700Schasinglulu 	wfi();
211*91f16700Schasinglulu 
212*91f16700Schasinglulu 	/*
213*91f16700Schasinglulu 	 * Restore SCR to the original value, synchronisation of scr_el3 is
214*91f16700Schasinglulu 	 * done by eret while el3_exit to save some execution cycles.
215*91f16700Schasinglulu 	 */
216*91f16700Schasinglulu 	write_scr_el3(scr);
217*91f16700Schasinglulu }
218*91f16700Schasinglulu 
219*91f16700Schasinglulu /*
220*91f16700Schasinglulu  * Helper function to shutdown the system via SCPI.
221*91f16700Schasinglulu  */
222*91f16700Schasinglulu static void __dead2 brcm_scp_sys_shutdown(void)
223*91f16700Schasinglulu {
224*91f16700Schasinglulu 	/*
225*91f16700Schasinglulu 	 * Disable GIC CPU interface to prevent pending interrupt
226*91f16700Schasinglulu 	 * from waking up the AP from WFI.
227*91f16700Schasinglulu 	 */
228*91f16700Schasinglulu 	plat_brcm_gic_cpuif_disable();
229*91f16700Schasinglulu 
230*91f16700Schasinglulu 	/* Flush and invalidate data cache */
231*91f16700Schasinglulu 	dcsw_op_all(DCCISW);
232*91f16700Schasinglulu 
233*91f16700Schasinglulu 	/* Bring Cluster out of coherency domain as its going to die */
234*91f16700Schasinglulu 	plat_brcm_interconnect_exit_coherency();
235*91f16700Schasinglulu 
236*91f16700Schasinglulu 	brcm_power_down_common();
237*91f16700Schasinglulu 
238*91f16700Schasinglulu 	/* Send the power down request to the SCP */
239*91f16700Schasinglulu 	scpi_sys_power_state(scpi_system_shutdown);
240*91f16700Schasinglulu 
241*91f16700Schasinglulu 	wfi();
242*91f16700Schasinglulu 	ERROR("BRCM System Off: operation not handled.\n");
243*91f16700Schasinglulu 	panic();
244*91f16700Schasinglulu }
245*91f16700Schasinglulu 
246*91f16700Schasinglulu /*
247*91f16700Schasinglulu  * Helper function to reset the system
248*91f16700Schasinglulu  */
249*91f16700Schasinglulu static void __dead2 brcm_scp_sys_reset(unsigned int reset_type)
250*91f16700Schasinglulu {
251*91f16700Schasinglulu 	/*
252*91f16700Schasinglulu 	 * Disable GIC CPU interface to prevent pending interrupt
253*91f16700Schasinglulu 	 * from waking up the AP from WFI.
254*91f16700Schasinglulu 	 */
255*91f16700Schasinglulu 	plat_brcm_gic_cpuif_disable();
256*91f16700Schasinglulu 
257*91f16700Schasinglulu 	/* Flush and invalidate data cache */
258*91f16700Schasinglulu 	dcsw_op_all(DCCISW);
259*91f16700Schasinglulu 
260*91f16700Schasinglulu 	/* Bring Cluster out of coherency domain as its going to die */
261*91f16700Schasinglulu 	plat_brcm_interconnect_exit_coherency();
262*91f16700Schasinglulu 
263*91f16700Schasinglulu 	brcm_power_down_common();
264*91f16700Schasinglulu 
265*91f16700Schasinglulu 	/* Send the system reset request to the SCP
266*91f16700Schasinglulu 	 *
267*91f16700Schasinglulu 	 * As per PSCI spec system power state could be
268*91f16700Schasinglulu 	 * 0-> Shutdown
269*91f16700Schasinglulu 	 * 1-> Reboot- Board level Reset
270*91f16700Schasinglulu 	 * 2-> Reset - SoC level Reset
271*91f16700Schasinglulu 	 *
272*91f16700Schasinglulu 	 * Spec allocates 8 bits, 2 nibble, for this. One nibble is sufficient
273*91f16700Schasinglulu 	 * for sending the state hence We are utilizing 2nd nibble for vendor
274*91f16700Schasinglulu 	 * define reset type.
275*91f16700Schasinglulu 	 */
276*91f16700Schasinglulu 	scpi_sys_power_state((reset_type << VENDOR_RST_TYPE_SHIFT) |
277*91f16700Schasinglulu 			     scpi_system_reboot);
278*91f16700Schasinglulu 
279*91f16700Schasinglulu 	wfi();
280*91f16700Schasinglulu 	ERROR("BRCM System Reset: operation not handled.\n");
281*91f16700Schasinglulu 	panic();
282*91f16700Schasinglulu }
283*91f16700Schasinglulu 
284*91f16700Schasinglulu static void __dead2 brcm_system_reset(void)
285*91f16700Schasinglulu {
286*91f16700Schasinglulu 	unsigned int reset_type;
287*91f16700Schasinglulu 
288*91f16700Schasinglulu 	if (bcm_chimp_is_nic_mode())
289*91f16700Schasinglulu 		reset_type = SOFT_RESET_L3;
290*91f16700Schasinglulu 	else
291*91f16700Schasinglulu 		reset_type = SOFT_SYS_RESET_L1;
292*91f16700Schasinglulu 
293*91f16700Schasinglulu 	brcm_scp_sys_reset(reset_type);
294*91f16700Schasinglulu }
295*91f16700Schasinglulu 
296*91f16700Schasinglulu static int brcm_system_reset2(int is_vendor, int reset_type,
297*91f16700Schasinglulu 		      u_register_t cookie)
298*91f16700Schasinglulu {
299*91f16700Schasinglulu 	if (!is_vendor) {
300*91f16700Schasinglulu 		/* Architectural warm boot: only warm reset is supported */
301*91f16700Schasinglulu 		reset_type = SOFT_RESET_L3;
302*91f16700Schasinglulu 	} else {
303*91f16700Schasinglulu 		uint32_t boot_source = (uint32_t)cookie;
304*91f16700Schasinglulu 
305*91f16700Schasinglulu 		boot_source &= BOOT_SOURCE_MASK;
306*91f16700Schasinglulu 		brcm_stingray_set_straps(boot_source);
307*91f16700Schasinglulu 	}
308*91f16700Schasinglulu 	brcm_scp_sys_reset(reset_type);
309*91f16700Schasinglulu 
310*91f16700Schasinglulu 	/*
311*91f16700Schasinglulu 	 * brcm_scp_sys_reset cannot return (it is a __dead function),
312*91f16700Schasinglulu 	 * but brcm_system_reset2 has to return some value, even in
313*91f16700Schasinglulu 	 * this case.
314*91f16700Schasinglulu 	 */
315*91f16700Schasinglulu 	return 0;
316*91f16700Schasinglulu }
317*91f16700Schasinglulu 
318*91f16700Schasinglulu static int brcm_validate_ns_entrypoint(uintptr_t entrypoint)
319*91f16700Schasinglulu {
320*91f16700Schasinglulu 	/*
321*91f16700Schasinglulu 	 * Check if the non secure entrypoint lies within the non
322*91f16700Schasinglulu 	 * secure DRAM.
323*91f16700Schasinglulu 	 */
324*91f16700Schasinglulu 	if ((entrypoint >= BRCM_NS_DRAM1_BASE) &&
325*91f16700Schasinglulu 	    (entrypoint < (BRCM_NS_DRAM1_BASE + BRCM_NS_DRAM1_SIZE)))
326*91f16700Schasinglulu 		return PSCI_E_SUCCESS;
327*91f16700Schasinglulu #ifdef __aarch64__
328*91f16700Schasinglulu 	if ((entrypoint >= BRCM_DRAM2_BASE) &&
329*91f16700Schasinglulu 	    (entrypoint < (BRCM_DRAM2_BASE + BRCM_DRAM2_SIZE)))
330*91f16700Schasinglulu 		return PSCI_E_SUCCESS;
331*91f16700Schasinglulu 
332*91f16700Schasinglulu 	if ((entrypoint >= BRCM_DRAM3_BASE) &&
333*91f16700Schasinglulu 	    (entrypoint < (BRCM_DRAM3_BASE + BRCM_DRAM3_SIZE)))
334*91f16700Schasinglulu 		return PSCI_E_SUCCESS;
335*91f16700Schasinglulu #endif
336*91f16700Schasinglulu 
337*91f16700Schasinglulu 	return PSCI_E_INVALID_ADDRESS;
338*91f16700Schasinglulu }
339*91f16700Schasinglulu 
340*91f16700Schasinglulu /*******************************************************************************
341*91f16700Schasinglulu  * ARM standard platform handler called to check the validity of the power state
342*91f16700Schasinglulu  * parameter.
343*91f16700Schasinglulu  ******************************************************************************/
344*91f16700Schasinglulu static int brcm_validate_power_state(unsigned int power_state,
345*91f16700Schasinglulu 			    psci_power_state_t *req_state)
346*91f16700Schasinglulu {
347*91f16700Schasinglulu 	int pstate = psci_get_pstate_type(power_state);
348*91f16700Schasinglulu 	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
349*91f16700Schasinglulu 	int i;
350*91f16700Schasinglulu 
351*91f16700Schasinglulu 	assert(req_state);
352*91f16700Schasinglulu 
353*91f16700Schasinglulu 	if (pwr_lvl > PLAT_MAX_PWR_LVL)
354*91f16700Schasinglulu 		return PSCI_E_INVALID_PARAMS;
355*91f16700Schasinglulu 
356*91f16700Schasinglulu 	/* Sanity check the requested state */
357*91f16700Schasinglulu 	if (pstate == PSTATE_TYPE_STANDBY) {
358*91f16700Schasinglulu 		/*
359*91f16700Schasinglulu 		 * It's possible to enter standby only on power level 0
360*91f16700Schasinglulu 		 * Ignore any other power level.
361*91f16700Schasinglulu 		 */
362*91f16700Schasinglulu 		if (pwr_lvl != MPIDR_AFFLVL0)
363*91f16700Schasinglulu 			return PSCI_E_INVALID_PARAMS;
364*91f16700Schasinglulu 
365*91f16700Schasinglulu 		req_state->pwr_domain_state[MPIDR_AFFLVL0] =
366*91f16700Schasinglulu 					PLAT_LOCAL_STATE_RET;
367*91f16700Schasinglulu 	} else {
368*91f16700Schasinglulu 		for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
369*91f16700Schasinglulu 			req_state->pwr_domain_state[i] =
370*91f16700Schasinglulu 					PLAT_LOCAL_STATE_OFF;
371*91f16700Schasinglulu 	}
372*91f16700Schasinglulu 
373*91f16700Schasinglulu 	/*
374*91f16700Schasinglulu 	 * We expect the 'state id' to be zero.
375*91f16700Schasinglulu 	 */
376*91f16700Schasinglulu 	if (psci_get_pstate_id(power_state))
377*91f16700Schasinglulu 		return PSCI_E_INVALID_PARAMS;
378*91f16700Schasinglulu 
379*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
380*91f16700Schasinglulu }
381*91f16700Schasinglulu 
382*91f16700Schasinglulu /*******************************************************************************
383*91f16700Schasinglulu  * Export the platform handlers via plat_brcm_psci_pm_ops. The ARM Standard
384*91f16700Schasinglulu  * platform will take care of registering the handlers with PSCI.
385*91f16700Schasinglulu  ******************************************************************************/
386*91f16700Schasinglulu plat_psci_ops_t plat_brcm_psci_pm_ops = {
387*91f16700Schasinglulu 	.pwr_domain_on		= brcm_pwr_domain_on,
388*91f16700Schasinglulu 	.pwr_domain_on_finish	= brcm_pwr_domain_on_finish,
389*91f16700Schasinglulu 	.pwr_domain_off		= brcm_pwr_domain_off,
390*91f16700Schasinglulu 	.cpu_standby		= brcm_cpu_standby,
391*91f16700Schasinglulu 	.system_off		= brcm_scp_sys_shutdown,
392*91f16700Schasinglulu 	.system_reset		= brcm_system_reset,
393*91f16700Schasinglulu 	.system_reset2		= brcm_system_reset2,
394*91f16700Schasinglulu 	.validate_ns_entrypoint = brcm_validate_ns_entrypoint,
395*91f16700Schasinglulu 	.validate_power_state	= brcm_validate_power_state,
396*91f16700Schasinglulu };
397*91f16700Schasinglulu 
398*91f16700Schasinglulu int plat_setup_psci_ops(uintptr_t sec_entrypoint,
399*91f16700Schasinglulu 			const struct plat_psci_ops **psci_ops)
400*91f16700Schasinglulu {
401*91f16700Schasinglulu 	*psci_ops = &plat_brcm_psci_pm_ops;
402*91f16700Schasinglulu 
403*91f16700Schasinglulu 	/* Setup mailbox with entry point. */
404*91f16700Schasinglulu 	mmio_write_64(CRMU_CFG_BASE + offsetof(M0CFG, core_cfg.rvbar),
405*91f16700Schasinglulu 		      sec_entrypoint);
406*91f16700Schasinglulu 
407*91f16700Schasinglulu 	return 0;
408*91f16700Schasinglulu }
409