xref: /rk3399_ARM-atf/plat/ti/k3/common/k3_psci.c (revision 6a655a85c09a6a1707b40993d261fbafc1f511c5)
12e9c9e82SBenjamin Fair /*
22e9c9e82SBenjamin Fair  * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
32e9c9e82SBenjamin Fair  *
42e9c9e82SBenjamin Fair  * SPDX-License-Identifier: BSD-3-Clause
52e9c9e82SBenjamin Fair  */
62e9c9e82SBenjamin Fair 
72e9c9e82SBenjamin Fair #include <arch_helpers.h>
82e9c9e82SBenjamin Fair #include <assert.h>
9*6a655a85SAndrew F. Davis #include <cpu_data.h>
102e9c9e82SBenjamin Fair #include <debug.h>
112e9c9e82SBenjamin Fair #include <k3_gicv3.h>
122e9c9e82SBenjamin Fair #include <psci.h>
13*6a655a85SAndrew F. Davis /* Need to flush psci internal locks before shutdown or their values are lost */
14*6a655a85SAndrew F. Davis #include <../../lib/psci/psci_private.h>
15df83b034SAndrew F. Davis #include <platform.h>
162e9c9e82SBenjamin Fair #include <stdbool.h>
172e9c9e82SBenjamin Fair 
18df83b034SAndrew F. Davis #include <ti_sci.h>
19df83b034SAndrew F. Davis 
202e9c9e82SBenjamin Fair #define STUB() ERROR("stub %s called\n", __func__)
212e9c9e82SBenjamin Fair 
222e9c9e82SBenjamin Fair uintptr_t k3_sec_entrypoint;
232e9c9e82SBenjamin Fair 
242e9c9e82SBenjamin Fair static void k3_cpu_standby(plat_local_state_t cpu_state)
252e9c9e82SBenjamin Fair {
26deed2b83SAndrew F. Davis 	unsigned int scr;
27deed2b83SAndrew F. Davis 
28deed2b83SAndrew F. Davis 	scr = read_scr_el3();
29deed2b83SAndrew F. Davis 	/* Enable the Non secure interrupt to wake the CPU */
30deed2b83SAndrew F. Davis 	write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
31deed2b83SAndrew F. Davis 	isb();
32deed2b83SAndrew F. Davis 	/* dsb is good practice before using wfi to enter low power states */
332e9c9e82SBenjamin Fair 	dsb();
34deed2b83SAndrew F. Davis 	/* Enter standby state */
352e9c9e82SBenjamin Fair 	wfi();
36deed2b83SAndrew F. Davis 	/* Restore SCR */
37deed2b83SAndrew F. Davis 	write_scr_el3(scr);
382e9c9e82SBenjamin Fair }
392e9c9e82SBenjamin Fair 
402e9c9e82SBenjamin Fair static int k3_pwr_domain_on(u_register_t mpidr)
412e9c9e82SBenjamin Fair {
42df83b034SAndrew F. Davis 	int core_id, proc, device, ret;
432e9c9e82SBenjamin Fair 
44df83b034SAndrew F. Davis 	core_id = plat_core_pos_by_mpidr(mpidr);
45df83b034SAndrew F. Davis 	if (core_id < 0) {
46df83b034SAndrew F. Davis 		ERROR("Could not get target core id: %d\n", core_id);
47df83b034SAndrew F. Davis 		return PSCI_E_INTERN_FAIL;
48df83b034SAndrew F. Davis 	}
49df83b034SAndrew F. Davis 
50df83b034SAndrew F. Davis 	proc = PLAT_PROC_START_ID + core_id;
51df83b034SAndrew F. Davis 	device = PLAT_PROC_DEVICE_START_ID + core_id;
52df83b034SAndrew F. Davis 
53df83b034SAndrew F. Davis 	ret = ti_sci_proc_request(proc);
54df83b034SAndrew F. Davis 	if (ret) {
55df83b034SAndrew F. Davis 		ERROR("Request for processor failed: %d\n", ret);
56df83b034SAndrew F. Davis 		return PSCI_E_INTERN_FAIL;
57df83b034SAndrew F. Davis 	}
58df83b034SAndrew F. Davis 
59df83b034SAndrew F. Davis 	ret = ti_sci_proc_set_boot_cfg(proc, k3_sec_entrypoint, 0, 0);
60df83b034SAndrew F. Davis 	if (ret) {
61df83b034SAndrew F. Davis 		ERROR("Request to set core boot address failed: %d\n", ret);
62df83b034SAndrew F. Davis 		return PSCI_E_INTERN_FAIL;
63df83b034SAndrew F. Davis 	}
64df83b034SAndrew F. Davis 
65df83b034SAndrew F. Davis 	ret = ti_sci_device_get(device);
66df83b034SAndrew F. Davis 	if (ret) {
67df83b034SAndrew F. Davis 		ERROR("Request to start core failed: %d\n", ret);
68df83b034SAndrew F. Davis 		return PSCI_E_INTERN_FAIL;
69df83b034SAndrew F. Davis 	}
70df83b034SAndrew F. Davis 
71df83b034SAndrew F. Davis 	ret = ti_sci_proc_release(proc);
72df83b034SAndrew F. Davis 	if (ret) {
73df83b034SAndrew F. Davis 		/* this is not fatal */
74df83b034SAndrew F. Davis 		WARN("Could not release processor control: %d\n", ret);
75df83b034SAndrew F. Davis 	}
762e9c9e82SBenjamin Fair 
772e9c9e82SBenjamin Fair 	return PSCI_E_SUCCESS;
782e9c9e82SBenjamin Fair }
792e9c9e82SBenjamin Fair 
802e9c9e82SBenjamin Fair void k3_pwr_domain_off(const psci_power_state_t *target_state)
812e9c9e82SBenjamin Fair {
8234cae37fSAndrew F. Davis 	int core_id, device, ret;
8334cae37fSAndrew F. Davis 
842e9c9e82SBenjamin Fair 	/* Prevent interrupts from spuriously waking up this cpu */
852e9c9e82SBenjamin Fair 	k3_gic_cpuif_disable();
862e9c9e82SBenjamin Fair 
8734cae37fSAndrew F. Davis 	core_id = plat_my_core_pos();
8834cae37fSAndrew F. Davis 	device = PLAT_PROC_DEVICE_START_ID + core_id;
8934cae37fSAndrew F. Davis 
9034cae37fSAndrew F. Davis 	ret = ti_sci_device_put(device);
9134cae37fSAndrew F. Davis 	if (ret) {
9234cae37fSAndrew F. Davis 		ERROR("Request to stop core failed: %d\n", ret);
9334cae37fSAndrew F. Davis 		return;
9434cae37fSAndrew F. Davis 	}
952e9c9e82SBenjamin Fair }
962e9c9e82SBenjamin Fair 
972e9c9e82SBenjamin Fair void k3_pwr_domain_on_finish(const psci_power_state_t *target_state)
982e9c9e82SBenjamin Fair {
992e9c9e82SBenjamin Fair 	/* TODO: Indicate to System firmware about completion */
1002e9c9e82SBenjamin Fair 
1012e9c9e82SBenjamin Fair 	k3_gic_pcpu_init();
1022e9c9e82SBenjamin Fair 	k3_gic_cpuif_enable();
1032e9c9e82SBenjamin Fair }
1042e9c9e82SBenjamin Fair 
105*6a655a85SAndrew F. Davis static void  __dead2 k3_pwr_domain_pwr_down_wfi(const psci_power_state_t
106*6a655a85SAndrew F. Davis 						  *target_state)
107*6a655a85SAndrew F. Davis {
108*6a655a85SAndrew F. Davis 	flush_cpu_data(psci_svc_cpu_data);
109*6a655a85SAndrew F. Davis 	flush_dcache_range((uintptr_t) psci_locks, sizeof(psci_locks));
110*6a655a85SAndrew F. Davis 	psci_power_down_wfi();
111*6a655a85SAndrew F. Davis }
112*6a655a85SAndrew F. Davis 
1132e9c9e82SBenjamin Fair static void __dead2 k3_system_reset(void)
1142e9c9e82SBenjamin Fair {
115c8761b4dSAndrew F. Davis 	/* Send the system reset request to system firmware */
116c8761b4dSAndrew F. Davis 	ti_sci_core_reboot();
1172e9c9e82SBenjamin Fair 
1182e9c9e82SBenjamin Fair 	while (true)
1192e9c9e82SBenjamin Fair 		wfi();
1202e9c9e82SBenjamin Fair }
1212e9c9e82SBenjamin Fair 
1222e9c9e82SBenjamin Fair static int k3_validate_power_state(unsigned int power_state,
1232e9c9e82SBenjamin Fair 				   psci_power_state_t *req_state)
1242e9c9e82SBenjamin Fair {
1252e9c9e82SBenjamin Fair 	/* TODO: perform the proper validation */
1262e9c9e82SBenjamin Fair 
1272e9c9e82SBenjamin Fair 	return PSCI_E_SUCCESS;
1282e9c9e82SBenjamin Fair }
1292e9c9e82SBenjamin Fair 
1302e9c9e82SBenjamin Fair static int k3_validate_ns_entrypoint(uintptr_t entrypoint)
1312e9c9e82SBenjamin Fair {
1322e9c9e82SBenjamin Fair 	/* TODO: perform the proper validation */
1332e9c9e82SBenjamin Fair 
1342e9c9e82SBenjamin Fair 	return PSCI_E_SUCCESS;
1352e9c9e82SBenjamin Fair }
1362e9c9e82SBenjamin Fair 
1372e9c9e82SBenjamin Fair static const plat_psci_ops_t k3_plat_psci_ops = {
1382e9c9e82SBenjamin Fair 	.cpu_standby = k3_cpu_standby,
1392e9c9e82SBenjamin Fair 	.pwr_domain_on = k3_pwr_domain_on,
1402e9c9e82SBenjamin Fair 	.pwr_domain_off = k3_pwr_domain_off,
1412e9c9e82SBenjamin Fair 	.pwr_domain_on_finish = k3_pwr_domain_on_finish,
142*6a655a85SAndrew F. Davis 	.pwr_domain_pwr_down_wfi = k3_pwr_domain_pwr_down_wfi,
1432e9c9e82SBenjamin Fair 	.system_reset = k3_system_reset,
1442e9c9e82SBenjamin Fair 	.validate_power_state = k3_validate_power_state,
1452e9c9e82SBenjamin Fair 	.validate_ns_entrypoint = k3_validate_ns_entrypoint
1462e9c9e82SBenjamin Fair };
1472e9c9e82SBenjamin Fair 
1482e9c9e82SBenjamin Fair int plat_setup_psci_ops(uintptr_t sec_entrypoint,
1492e9c9e82SBenjamin Fair 			const plat_psci_ops_t **psci_ops)
1502e9c9e82SBenjamin Fair {
1512e9c9e82SBenjamin Fair 	k3_sec_entrypoint = sec_entrypoint;
1522e9c9e82SBenjamin Fair 
1532e9c9e82SBenjamin Fair 	*psci_ops = &k3_plat_psci_ops;
1542e9c9e82SBenjamin Fair 
1552e9c9e82SBenjamin Fair 	return 0;
1562e9c9e82SBenjamin Fair }
157