xref: /rk3399_ARM-atf/plat/nuvoton/npcm845x/npcm845x_psci.c (revision edcece15c76423832fc1ffdb255528bf4c719516)
1*edcece15Srutigl@gmail.com /*
2*edcece15Srutigl@gmail.com  * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved.
3*edcece15Srutigl@gmail.com  *
4*edcece15Srutigl@gmail.com  * Copyright (C) 2017-2023 Nuvoton Ltd.
5*edcece15Srutigl@gmail.com  *
6*edcece15Srutigl@gmail.com  * SPDX-License-Identifier: BSD-3-Clause
7*edcece15Srutigl@gmail.com  */
8*edcece15Srutigl@gmail.com 
9*edcece15Srutigl@gmail.com #include <assert.h>
10*edcece15Srutigl@gmail.com #include <stdbool.h>
11*edcece15Srutigl@gmail.com 
12*edcece15Srutigl@gmail.com #include <arch.h>
13*edcece15Srutigl@gmail.com #include <arch_helpers.h>
14*edcece15Srutigl@gmail.com #include <common/debug.h>
15*edcece15Srutigl@gmail.com #include <drivers/arm/gicv2.h>
16*edcece15Srutigl@gmail.com #include <lib/mmio.h>
17*edcece15Srutigl@gmail.com #include <lib/psci/psci.h>
18*edcece15Srutigl@gmail.com #include <lib/semihosting.h>
19*edcece15Srutigl@gmail.com #include <npcm845x_clock.h>
20*edcece15Srutigl@gmail.com #include <plat/arm/common/plat_arm.h>
21*edcece15Srutigl@gmail.com #include <plat/common/platform.h>
22*edcece15Srutigl@gmail.com #include <plat_npcm845x.h>
23*edcece15Srutigl@gmail.com 
24*edcece15Srutigl@gmail.com #define ADP_STOPPED_APPLICATION_EXIT 0x20026
25*edcece15Srutigl@gmail.com 
26*edcece15Srutigl@gmail.com /* Make composite power state parameter till power level 0 */
27*edcece15Srutigl@gmail.com #if PSCI_EXTENDED_STATE_ID
28*edcece15Srutigl@gmail.com /* Not Extended */
29*edcece15Srutigl@gmail.com #define npcm845x_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
30*edcece15Srutigl@gmail.com 		(((lvl0_state) << PSTATE_ID_SHIFT) | \
31*edcece15Srutigl@gmail.com 		 ((type) << PSTATE_TYPE_SHIFT))
32*edcece15Srutigl@gmail.com #else
33*edcece15Srutigl@gmail.com #define npcm845x_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
34*edcece15Srutigl@gmail.com 		(((lvl0_state) << PSTATE_ID_SHIFT) | \
35*edcece15Srutigl@gmail.com 		 ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \
36*edcece15Srutigl@gmail.com 		 ((type) << PSTATE_TYPE_SHIFT))
37*edcece15Srutigl@gmail.com #endif /* PSCI_EXTENDED_STATE_ID */
38*edcece15Srutigl@gmail.com 
39*edcece15Srutigl@gmail.com #define npcm845x_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \
40*edcece15Srutigl@gmail.com 		(((lvl1_state) << PLAT_LOCAL_PSTATE_WIDTH) | \
41*edcece15Srutigl@gmail.com 		 npcm845x_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type))
42*edcece15Srutigl@gmail.com 
43*edcece15Srutigl@gmail.com /*
44*edcece15Srutigl@gmail.com  * The table storing the valid idle power states. Ensure that the
45*edcece15Srutigl@gmail.com  * array entries are populated in ascending order of state-id to
46*edcece15Srutigl@gmail.com  * enable us to use binary search during power state validation.
47*edcece15Srutigl@gmail.com  * The table must be terminated by a NULL entry.
48*edcece15Srutigl@gmail.com  */
49*edcece15Srutigl@gmail.com static const unsigned int npcm845x_pm_idle_states[] = {
50*edcece15Srutigl@gmail.com /*
51*edcece15Srutigl@gmail.com  * Cluster = 0 (RUN) CPU=1 (RET, higest in idle) -
52*edcece15Srutigl@gmail.com  * Retention. The Power state is Stand-by
53*edcece15Srutigl@gmail.com  */
54*edcece15Srutigl@gmail.com 
55*edcece15Srutigl@gmail.com /* State-id - 0x01 */
56*edcece15Srutigl@gmail.com 	npcm845x_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_RET,
57*edcece15Srutigl@gmail.com 				MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY),
58*edcece15Srutigl@gmail.com 
59*edcece15Srutigl@gmail.com /*
60*edcece15Srutigl@gmail.com  * For testing purposes.
61*edcece15Srutigl@gmail.com  * Only CPU suspend to standby is supported by NPCM845x
62*edcece15Srutigl@gmail.com  */
63*edcece15Srutigl@gmail.com 	/* State-id - 0x02 */
64*edcece15Srutigl@gmail.com 	npcm845x_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_OFF,
65*edcece15Srutigl@gmail.com 				MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN),
66*edcece15Srutigl@gmail.com 	0,
67*edcece15Srutigl@gmail.com };
68*edcece15Srutigl@gmail.com 
69*edcece15Srutigl@gmail.com /*******************************************************************************
70*edcece15Srutigl@gmail.com  * Platform handler called to check the validity of the non secure
71*edcece15Srutigl@gmail.com  * entrypoint.
72*edcece15Srutigl@gmail.com  ******************************************************************************/
73*edcece15Srutigl@gmail.com int npcm845x_validate_ns_entrypoint(uintptr_t entrypoint)
74*edcece15Srutigl@gmail.com {
75*edcece15Srutigl@gmail.com 	/*
76*edcece15Srutigl@gmail.com 	 * Check if the non secure entrypoint lies within the non
77*edcece15Srutigl@gmail.com 	 * secure DRAM.
78*edcece15Srutigl@gmail.com 	 */
79*edcece15Srutigl@gmail.com 	NOTICE("%s() nuvoton_psci\n", __func__);
80*edcece15Srutigl@gmail.com #ifdef PLAT_ARM_TRUSTED_DRAM_BASE
81*edcece15Srutigl@gmail.com 	if ((entrypoint >= PLAT_ARM_TRUSTED_DRAM_BASE) &&
82*edcece15Srutigl@gmail.com 		(entrypoint < (PLAT_ARM_TRUSTED_DRAM_BASE +
83*edcece15Srutigl@gmail.com 		PLAT_ARM_TRUSTED_DRAM_SIZE))) {
84*edcece15Srutigl@gmail.com 		return PSCI_E_INVALID_ADDRESS;
85*edcece15Srutigl@gmail.com 	}
86*edcece15Srutigl@gmail.com #endif /* PLAT_ARM_TRUSTED_DRAM_BASE */
87*edcece15Srutigl@gmail.com 	/* For TFTS purposes, '0' is also illegal */
88*edcece15Srutigl@gmail.com 	#ifdef SPD_tspd
89*edcece15Srutigl@gmail.com 		if (entrypoint == 0) {
90*edcece15Srutigl@gmail.com 			return PSCI_E_INVALID_ADDRESS;
91*edcece15Srutigl@gmail.com 		}
92*edcece15Srutigl@gmail.com 	#endif /* SPD_tspd */
93*edcece15Srutigl@gmail.com 	return PSCI_E_SUCCESS;
94*edcece15Srutigl@gmail.com }
95*edcece15Srutigl@gmail.com 
96*edcece15Srutigl@gmail.com /*******************************************************************************
97*edcece15Srutigl@gmail.com  * Platform handler called when a CPU is about to enter standby.
98*edcece15Srutigl@gmail.com  ******************************************************************************/
99*edcece15Srutigl@gmail.com void npcm845x_cpu_standby(plat_local_state_t cpu_state)
100*edcece15Srutigl@gmail.com {
101*edcece15Srutigl@gmail.com 	NOTICE("%s() nuvoton_psci\n", __func__);
102*edcece15Srutigl@gmail.com 
103*edcece15Srutigl@gmail.com 	uint64_t scr;
104*edcece15Srutigl@gmail.com 
105*edcece15Srutigl@gmail.com 	scr = read_scr_el3();
106*edcece15Srutigl@gmail.com 	write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
107*edcece15Srutigl@gmail.com 
108*edcece15Srutigl@gmail.com 	/*
109*edcece15Srutigl@gmail.com 	 * Enter standby state
110*edcece15Srutigl@gmail.com 	 * dsb is good practice before using wfi to enter low power states
111*edcece15Srutigl@gmail.com 	 */
112*edcece15Srutigl@gmail.com 	isb();
113*edcece15Srutigl@gmail.com 	dsb();
114*edcece15Srutigl@gmail.com 	wfi();
115*edcece15Srutigl@gmail.com 
116*edcece15Srutigl@gmail.com 	/* Once awake */
117*edcece15Srutigl@gmail.com 	write_scr_el3(scr);
118*edcece15Srutigl@gmail.com }
119*edcece15Srutigl@gmail.com 
120*edcece15Srutigl@gmail.com /*******************************************************************************
121*edcece15Srutigl@gmail.com  * Platform handler called when a power domain is about to be turned on. The
122*edcece15Srutigl@gmail.com  * mpidr determines the CPU to be turned on.
123*edcece15Srutigl@gmail.com  ******************************************************************************/
124*edcece15Srutigl@gmail.com int npcm845x_pwr_domain_on(u_register_t mpidr)
125*edcece15Srutigl@gmail.com {
126*edcece15Srutigl@gmail.com 	int rc = PSCI_E_SUCCESS;
127*edcece15Srutigl@gmail.com 	int cpu_id = plat_core_pos_by_mpidr(mpidr);
128*edcece15Srutigl@gmail.com 
129*edcece15Srutigl@gmail.com 	if ((unsigned int)cpu_id >= PLATFORM_CORE_COUNT) {
130*edcece15Srutigl@gmail.com 		ERROR("%s()  CPU 0x%X\n", __func__, cpu_id);
131*edcece15Srutigl@gmail.com 		return PSCI_E_INVALID_PARAMS;
132*edcece15Srutigl@gmail.com 	}
133*edcece15Srutigl@gmail.com 
134*edcece15Srutigl@gmail.com 	if (cpu_id == -1) {
135*edcece15Srutigl@gmail.com 		/* domain on was not called by a CPU */
136*edcece15Srutigl@gmail.com 		ERROR("%s() was not per CPU 0x%X\n", __func__, cpu_id);
137*edcece15Srutigl@gmail.com 		return PSCI_E_INVALID_PARAMS;
138*edcece15Srutigl@gmail.com 	}
139*edcece15Srutigl@gmail.com 
140*edcece15Srutigl@gmail.com 	unsigned int pos = (unsigned int)plat_core_pos_by_mpidr(mpidr);
141*edcece15Srutigl@gmail.com 	uintptr_t hold_base = PLAT_NPCM_TM_HOLD_BASE;
142*edcece15Srutigl@gmail.com 
143*edcece15Srutigl@gmail.com 	assert(pos < PLATFORM_CORE_COUNT);
144*edcece15Srutigl@gmail.com 
145*edcece15Srutigl@gmail.com 	hold_base += pos * PLAT_NPCM_TM_HOLD_ENTRY_SIZE;
146*edcece15Srutigl@gmail.com 
147*edcece15Srutigl@gmail.com 	mmio_write_64(hold_base, PLAT_NPCM_TM_HOLD_STATE_GO);
148*edcece15Srutigl@gmail.com 	/* No cache maintenance here, hold_base is mapped as device memory. */
149*edcece15Srutigl@gmail.com 
150*edcece15Srutigl@gmail.com 	/* Make sure that the write has completed */
151*edcece15Srutigl@gmail.com 	dsb();
152*edcece15Srutigl@gmail.com 	isb();
153*edcece15Srutigl@gmail.com 
154*edcece15Srutigl@gmail.com 	sev();
155*edcece15Srutigl@gmail.com 
156*edcece15Srutigl@gmail.com 	return rc;
157*edcece15Srutigl@gmail.com }
158*edcece15Srutigl@gmail.com 
159*edcece15Srutigl@gmail.com 
160*edcece15Srutigl@gmail.com /*******************************************************************************
161*edcece15Srutigl@gmail.com  * Platform handler called when a power domain is about to be suspended. The
162*edcece15Srutigl@gmail.com  * target_state encodes the power state that each level should transition to.
163*edcece15Srutigl@gmail.com  ******************************************************************************/
164*edcece15Srutigl@gmail.com void npcm845x_pwr_domain_suspend(const psci_power_state_t *target_state)
165*edcece15Srutigl@gmail.com {
166*edcece15Srutigl@gmail.com 	NOTICE("%s() nuvoton_psci\n", __func__);
167*edcece15Srutigl@gmail.com 
168*edcece15Srutigl@gmail.com 	for (size_t i = 0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) {
169*edcece15Srutigl@gmail.com 		INFO("%s: target_state->pwr_domain_state[%lu]=%x\n",
170*edcece15Srutigl@gmail.com 			__func__, i, target_state->pwr_domain_state[i]);
171*edcece15Srutigl@gmail.com 	}
172*edcece15Srutigl@gmail.com 
173*edcece15Srutigl@gmail.com 	gicv2_cpuif_disable();
174*edcece15Srutigl@gmail.com 
175*edcece15Srutigl@gmail.com 	NOTICE("%s() Out of suspend\n", __func__);
176*edcece15Srutigl@gmail.com }
177*edcece15Srutigl@gmail.com 
178*edcece15Srutigl@gmail.com 
179*edcece15Srutigl@gmail.com /*******************************************************************************
180*edcece15Srutigl@gmail.com  * Platform handler called when a power domain has just been powered on after
181*edcece15Srutigl@gmail.com  * being turned off earlier. The target_state encodes the low power state that
182*edcece15Srutigl@gmail.com  * each level has woken up from.
183*edcece15Srutigl@gmail.com  ******************************************************************************/
184*edcece15Srutigl@gmail.com void npcm845x_pwr_domain_on_finish(const psci_power_state_t *target_state)
185*edcece15Srutigl@gmail.com {
186*edcece15Srutigl@gmail.com 	NOTICE("%s() nuvoton_psci\n", __func__);
187*edcece15Srutigl@gmail.com 
188*edcece15Srutigl@gmail.com 	for (size_t i = 0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) {
189*edcece15Srutigl@gmail.com 		INFO("%s: target_state->pwr_domain_state[%lu]=%x\n",
190*edcece15Srutigl@gmail.com 			__func__, i, target_state->pwr_domain_state[i]);
191*edcece15Srutigl@gmail.com 	}
192*edcece15Srutigl@gmail.com 
193*edcece15Srutigl@gmail.com 	assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
194*edcece15Srutigl@gmail.com 			PLAT_LOCAL_STATE_OFF);
195*edcece15Srutigl@gmail.com 
196*edcece15Srutigl@gmail.com 	gicv2_pcpu_distif_init();
197*edcece15Srutigl@gmail.com 	gicv2_cpuif_enable();
198*edcece15Srutigl@gmail.com }
199*edcece15Srutigl@gmail.com 
200*edcece15Srutigl@gmail.com 
201*edcece15Srutigl@gmail.com /*******************************************************************************
202*edcece15Srutigl@gmail.com  * Platform handler called when a power domain has just been powered on after
203*edcece15Srutigl@gmail.com  * having been suspended earlier. The target_state encodes the low power state
204*edcece15Srutigl@gmail.com  * that each level has woken up from.
205*edcece15Srutigl@gmail.com  ******************************************************************************/
206*edcece15Srutigl@gmail.com void npcm845x_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
207*edcece15Srutigl@gmail.com {
208*edcece15Srutigl@gmail.com 	NOTICE("%s() nuvoton_psci\n", __func__);
209*edcece15Srutigl@gmail.com 
210*edcece15Srutigl@gmail.com 	for (size_t i = 0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) {
211*edcece15Srutigl@gmail.com 		INFO("%s: target_state->pwr_domain_state[%lu]=%x\n",
212*edcece15Srutigl@gmail.com 			__func__, i, target_state->pwr_domain_state[i]);
213*edcece15Srutigl@gmail.com 	}
214*edcece15Srutigl@gmail.com 
215*edcece15Srutigl@gmail.com 	assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
216*edcece15Srutigl@gmail.com 			PLAT_LOCAL_STATE_OFF);
217*edcece15Srutigl@gmail.com 
218*edcece15Srutigl@gmail.com 	gicv2_pcpu_distif_init();
219*edcece15Srutigl@gmail.com 	gicv2_cpuif_enable();
220*edcece15Srutigl@gmail.com }
221*edcece15Srutigl@gmail.com 
222*edcece15Srutigl@gmail.com 
223*edcece15Srutigl@gmail.com void __dead2 npcm845x_system_reset(void)
224*edcece15Srutigl@gmail.com {
225*edcece15Srutigl@gmail.com 	uintptr_t RESET_BASE_ADDR;
226*edcece15Srutigl@gmail.com 	uint32_t val;
227*edcece15Srutigl@gmail.com 
228*edcece15Srutigl@gmail.com 	NOTICE("%s() nuvoton_psci\n", __func__);
229*edcece15Srutigl@gmail.com 	console_flush();
230*edcece15Srutigl@gmail.com 
231*edcece15Srutigl@gmail.com 	dsbsy();
232*edcece15Srutigl@gmail.com 	isb();
233*edcece15Srutigl@gmail.com 
234*edcece15Srutigl@gmail.com 	/*
235*edcece15Srutigl@gmail.com 	 * In future - support all reset types. For now, SW1 reset
236*edcece15Srutigl@gmail.com 	 * Enable software reset 1 to reboot the BMC
237*edcece15Srutigl@gmail.com 	 */
238*edcece15Srutigl@gmail.com 	RESET_BASE_ADDR = (uintptr_t)0xF0801000;
239*edcece15Srutigl@gmail.com 
240*edcece15Srutigl@gmail.com 	/* Read SW1 control register */
241*edcece15Srutigl@gmail.com 	val = mmio_read_32(RESET_BASE_ADDR + 0x44);
242*edcece15Srutigl@gmail.com 	/* Keep SPI BMC & MC persist*/
243*edcece15Srutigl@gmail.com 	val &= 0xFBFFFFDF;
244*edcece15Srutigl@gmail.com 	/* Setting SW1 control register */
245*edcece15Srutigl@gmail.com 	mmio_write_32(RESET_BASE_ADDR + 0x44, val);
246*edcece15Srutigl@gmail.com 	/* Set SW1 reset */
247*edcece15Srutigl@gmail.com 	mmio_write_32(RESET_BASE_ADDR + 0x14, 0x8);
248*edcece15Srutigl@gmail.com 	dsb();
249*edcece15Srutigl@gmail.com 
250*edcece15Srutigl@gmail.com 	while (1) {
251*edcece15Srutigl@gmail.com 		;
252*edcece15Srutigl@gmail.com 	}
253*edcece15Srutigl@gmail.com }
254*edcece15Srutigl@gmail.com 
255*edcece15Srutigl@gmail.com int npcm845x_validate_power_state(unsigned int power_state,
256*edcece15Srutigl@gmail.com 			 psci_power_state_t *req_state)
257*edcece15Srutigl@gmail.com {
258*edcece15Srutigl@gmail.com 	unsigned int state_id;
259*edcece15Srutigl@gmail.com 	int i;
260*edcece15Srutigl@gmail.com 
261*edcece15Srutigl@gmail.com 	NOTICE("%s() nuvoton_psci\n", __func__);
262*edcece15Srutigl@gmail.com 	assert(req_state);
263*edcece15Srutigl@gmail.com 
264*edcece15Srutigl@gmail.com 	/*
265*edcece15Srutigl@gmail.com 	 *  Currently we are using a linear search for finding the matching
266*edcece15Srutigl@gmail.com 	 *  entry in the idle power state array. This can be made a binary
267*edcece15Srutigl@gmail.com 	 *  search if the number of entries justify the additional complexity.
268*edcece15Srutigl@gmail.com 	 */
269*edcece15Srutigl@gmail.com 	for (i = 0; !!npcm845x_pm_idle_states[i]; i++) {
270*edcece15Srutigl@gmail.com 		if (power_state == npcm845x_pm_idle_states[i]) {
271*edcece15Srutigl@gmail.com 			break;
272*edcece15Srutigl@gmail.com 		}
273*edcece15Srutigl@gmail.com 	}
274*edcece15Srutigl@gmail.com 
275*edcece15Srutigl@gmail.com 	/* Return error if entry not found in the idle state array */
276*edcece15Srutigl@gmail.com 	if (!npcm845x_pm_idle_states[i]) {
277*edcece15Srutigl@gmail.com 		return PSCI_E_INVALID_PARAMS;
278*edcece15Srutigl@gmail.com 	}
279*edcece15Srutigl@gmail.com 
280*edcece15Srutigl@gmail.com 	i = 0;
281*edcece15Srutigl@gmail.com 	state_id = psci_get_pstate_id(power_state);
282*edcece15Srutigl@gmail.com 
283*edcece15Srutigl@gmail.com 	/* Parse the State ID and populate the state info parameter */
284*edcece15Srutigl@gmail.com 	while (state_id) {
285*edcece15Srutigl@gmail.com 		req_state->pwr_domain_state[i++] = (uint8_t)state_id &
286*edcece15Srutigl@gmail.com 						PLAT_LOCAL_PSTATE_MASK;
287*edcece15Srutigl@gmail.com 		state_id >>= PLAT_LOCAL_PSTATE_WIDTH;
288*edcece15Srutigl@gmail.com 	}
289*edcece15Srutigl@gmail.com 
290*edcece15Srutigl@gmail.com 	return PSCI_E_SUCCESS;
291*edcece15Srutigl@gmail.com }
292*edcece15Srutigl@gmail.com 
293*edcece15Srutigl@gmail.com /*
294*edcece15Srutigl@gmail.com  * The NPCM845 doesn't truly support power management at SYSTEM power domain.
295*edcece15Srutigl@gmail.com  * The SYSTEM_SUSPEND will be down-graded to the cluster level within
296*edcece15Srutigl@gmail.com  * the platform layer. The `fake` SYSTEM_SUSPEND allows us to validate
297*edcece15Srutigl@gmail.com  * some of the driver save and restore sequences on FVP.
298*edcece15Srutigl@gmail.com  */
299*edcece15Srutigl@gmail.com #if !ARM_BL31_IN_DRAM
300*edcece15Srutigl@gmail.com void npcm845x_get_sys_suspend_power_state(psci_power_state_t *req_state)
301*edcece15Srutigl@gmail.com {
302*edcece15Srutigl@gmail.com 	unsigned int i;
303*edcece15Srutigl@gmail.com 
304*edcece15Srutigl@gmail.com 	NOTICE("%s() nuvoton_psci\n", __func__);
305*edcece15Srutigl@gmail.com 
306*edcece15Srutigl@gmail.com 	for (i = ARM_PWR_LVL0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) {
307*edcece15Srutigl@gmail.com 		req_state->pwr_domain_state[i] = (uint8_t)PLAT_LOCAL_STATE_OFF;
308*edcece15Srutigl@gmail.com 	}
309*edcece15Srutigl@gmail.com }
310*edcece15Srutigl@gmail.com #endif /* !ARM_BL31_IN_DRAM */
311*edcece15Srutigl@gmail.com 
312*edcece15Srutigl@gmail.com /*
313*edcece15Srutigl@gmail.com  * The rest of the PSCI implementation are for testing purposes only.
314*edcece15Srutigl@gmail.com  * Not supported in Arbel
315*edcece15Srutigl@gmail.com  */
316*edcece15Srutigl@gmail.com void __dead2 npcm845x_system_off(void)
317*edcece15Srutigl@gmail.com {
318*edcece15Srutigl@gmail.com 	console_flush();
319*edcece15Srutigl@gmail.com 
320*edcece15Srutigl@gmail.com 	dsbsy();
321*edcece15Srutigl@gmail.com 	isb();
322*edcece15Srutigl@gmail.com 
323*edcece15Srutigl@gmail.com 	/* NPCM845 doesn't allow real system off, Do reaset instead */
324*edcece15Srutigl@gmail.com 	/* Do reset here TBD which, in the meanwhile SW1 reset */
325*edcece15Srutigl@gmail.com 	for (;;) {
326*edcece15Srutigl@gmail.com 		wfi();
327*edcece15Srutigl@gmail.com 	}
328*edcece15Srutigl@gmail.com }
329*edcece15Srutigl@gmail.com 
330*edcece15Srutigl@gmail.com void __dead2 plat_secondary_cold_boot_setup(void);
331*edcece15Srutigl@gmail.com 
332*edcece15Srutigl@gmail.com void __dead2 npcm845x_pwr_down_wfi(
333*edcece15Srutigl@gmail.com 		const psci_power_state_t *target_state)
334*edcece15Srutigl@gmail.com {
335*edcece15Srutigl@gmail.com 	uintptr_t hold_base = PLAT_NPCM_TM_HOLD_BASE;
336*edcece15Srutigl@gmail.com 	unsigned int pos = plat_my_core_pos();
337*edcece15Srutigl@gmail.com 
338*edcece15Srutigl@gmail.com 	if (pos == 0) {
339*edcece15Srutigl@gmail.com 		/*
340*edcece15Srutigl@gmail.com 		 * The secondaries will always be in a wait
341*edcece15Srutigl@gmail.com 		 * for warm boot on reset, but the BSP needs
342*edcece15Srutigl@gmail.com 		 * to be able to distinguish between waiting
343*edcece15Srutigl@gmail.com 		 * for warm boot (e.g. after psci_off, waiting
344*edcece15Srutigl@gmail.com 		 * for psci_on) and a cold boot.
345*edcece15Srutigl@gmail.com 		 */
346*edcece15Srutigl@gmail.com 		mmio_write_64(hold_base, PLAT_NPCM_TM_HOLD_STATE_BSP_OFF);
347*edcece15Srutigl@gmail.com 		/* No cache maintenance here, we run with caches off already. */
348*edcece15Srutigl@gmail.com 		dsb();
349*edcece15Srutigl@gmail.com 		isb();
350*edcece15Srutigl@gmail.com 	}
351*edcece15Srutigl@gmail.com 
352*edcece15Srutigl@gmail.com 	wfe();
353*edcece15Srutigl@gmail.com 
354*edcece15Srutigl@gmail.com 	while (1) {
355*edcece15Srutigl@gmail.com 		;
356*edcece15Srutigl@gmail.com 	}
357*edcece15Srutigl@gmail.com }
358*edcece15Srutigl@gmail.com 
359*edcece15Srutigl@gmail.com /*******************************************************************************
360*edcece15Srutigl@gmail.com  * Platform handler called when a power domain is about to be turned off. The
361*edcece15Srutigl@gmail.com  * target_state encodes the power state that each level should transition to.
362*edcece15Srutigl@gmail.com  ******************************************************************************/
363*edcece15Srutigl@gmail.com void npcm845x_pwr_domain_off(const psci_power_state_t *target_state)
364*edcece15Srutigl@gmail.com {
365*edcece15Srutigl@gmail.com 	NOTICE("%s() nuvoton_psci\n", __func__);
366*edcece15Srutigl@gmail.com 
367*edcece15Srutigl@gmail.com 	for (size_t i = 0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) {
368*edcece15Srutigl@gmail.com 		INFO("%s: target_state->pwr_domain_state[%lu]=%x\n",
369*edcece15Srutigl@gmail.com 			__func__, i, target_state->pwr_domain_state[i]);
370*edcece15Srutigl@gmail.com 	}
371*edcece15Srutigl@gmail.com 
372*edcece15Srutigl@gmail.com 	plat_secondary_cold_boot_setup();
373*edcece15Srutigl@gmail.com }
374*edcece15Srutigl@gmail.com 
375*edcece15Srutigl@gmail.com static const plat_psci_ops_t npcm845x_plat_psci_ops = {
376*edcece15Srutigl@gmail.com 	.cpu_standby = npcm845x_cpu_standby,
377*edcece15Srutigl@gmail.com 	.pwr_domain_on = npcm845x_pwr_domain_on,
378*edcece15Srutigl@gmail.com 	.pwr_domain_suspend = npcm845x_pwr_domain_suspend,
379*edcece15Srutigl@gmail.com 	.pwr_domain_on_finish = npcm845x_pwr_domain_on_finish,
380*edcece15Srutigl@gmail.com 	.pwr_domain_suspend_finish = npcm845x_pwr_domain_suspend_finish,
381*edcece15Srutigl@gmail.com 	.system_reset = npcm845x_system_reset,
382*edcece15Srutigl@gmail.com 	.validate_power_state = npcm845x_validate_power_state,
383*edcece15Srutigl@gmail.com 	.validate_ns_entrypoint = npcm845x_validate_ns_entrypoint,
384*edcece15Srutigl@gmail.com 
385*edcece15Srutigl@gmail.com 	/* For testing purposes only This PSCI states are not supported */
386*edcece15Srutigl@gmail.com 	.pwr_domain_off = npcm845x_pwr_domain_off,
387*edcece15Srutigl@gmail.com 	.pwr_domain_pwr_down_wfi = npcm845x_pwr_down_wfi,
388*edcece15Srutigl@gmail.com };
389*edcece15Srutigl@gmail.com 
390*edcece15Srutigl@gmail.com /* For reference only
391*edcece15Srutigl@gmail.com  * typedef struct plat_psci_ops {
392*edcece15Srutigl@gmail.com  *	void (*cpu_standby)(plat_local_state_t cpu_state);
393*edcece15Srutigl@gmail.com  *	int (*pwr_domain_on)(u_register_t mpidr);
394*edcece15Srutigl@gmail.com  *	void (*pwr_domain_off)(const psci_power_state_t *target_state);
395*edcece15Srutigl@gmail.com  *	void (*pwr_domain_suspend_pwrdown_early)(
396*edcece15Srutigl@gmail.com  *				const psci_power_state_t *target_state);
397*edcece15Srutigl@gmail.com  *	void (*pwr_domain_suspend)(const psci_power_state_t *target_state);
398*edcece15Srutigl@gmail.com  *	void (*pwr_domain_on_finish)(const psci_power_state_t *target_state);
399*edcece15Srutigl@gmail.com  *	void (*pwr_domain_on_finish_late)(
400*edcece15Srutigl@gmail.com  *				const psci_power_state_t *target_state);
401*edcece15Srutigl@gmail.com  *	void (*pwr_domain_suspend_finish)(
402*edcece15Srutigl@gmail.com  *				const psci_power_state_t *target_state);
403*edcece15Srutigl@gmail.com  *	void __dead2 (*pwr_domain_pwr_down_wfi)(
404*edcece15Srutigl@gmail.com  *				const psci_power_state_t *target_state);
405*edcece15Srutigl@gmail.com  *	void __dead2 (*system_off)(void);
406*edcece15Srutigl@gmail.com  *	void __dead2 (*system_reset)(void);
407*edcece15Srutigl@gmail.com  *	int (*validate_power_state)(unsigned int power_state,
408*edcece15Srutigl@gmail.com  *				psci_power_state_t *req_state);
409*edcece15Srutigl@gmail.com  *	int (*validate_ns_entrypoint)(uintptr_t ns_entrypoint);
410*edcece15Srutigl@gmail.com  *	void (*get_sys_suspend_power_state)(
411*edcece15Srutigl@gmail.com  *				psci_power_state_t *req_state);
412*edcece15Srutigl@gmail.com  *	int (*get_pwr_lvl_state_idx)(plat_local_state_t pwr_domain_state,
413*edcece15Srutigl@gmail.com  *				int pwrlvl);
414*edcece15Srutigl@gmail.com  *	int (*translate_power_state_by_mpidr)(u_register_t mpidr,
415*edcece15Srutigl@gmail.com  *				unsigned int power_state,
416*edcece15Srutigl@gmail.com  *				psci_power_state_t *output_state);
417*edcece15Srutigl@gmail.com  *	int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level);
418*edcece15Srutigl@gmail.com  *	int (*mem_protect_chk)(uintptr_t base, u_register_t length);
419*edcece15Srutigl@gmail.com  *	int (*read_mem_protect)(int *val);
420*edcece15Srutigl@gmail.com  *	int (*write_mem_protect)(int val);
421*edcece15Srutigl@gmail.com  *	int (*system_reset2)(int is_vendor,
422*edcece15Srutigl@gmail.com  *				int reset_type, u_register_t cookie);
423*edcece15Srutigl@gmail.com  * } plat_psci_ops_t;
424*edcece15Srutigl@gmail.com  */
425*edcece15Srutigl@gmail.com 
426*edcece15Srutigl@gmail.com int plat_setup_psci_ops(uintptr_t sec_entrypoint,
427*edcece15Srutigl@gmail.com 			const plat_psci_ops_t **psci_ops)
428*edcece15Srutigl@gmail.com {
429*edcece15Srutigl@gmail.com 	uintptr_t *entrypoint = (void *)PLAT_NPCM_TM_ENTRYPOINT;
430*edcece15Srutigl@gmail.com 
431*edcece15Srutigl@gmail.com 	*entrypoint = sec_entrypoint;
432*edcece15Srutigl@gmail.com 
433*edcece15Srutigl@gmail.com 	*psci_ops = &npcm845x_plat_psci_ops;
434*edcece15Srutigl@gmail.com 
435*edcece15Srutigl@gmail.com 	return 0;
436*edcece15Srutigl@gmail.com }
437