xref: /rk3399_ARM-atf/plat/ti/k3/common/k3_psci.c (revision f363deb6d409e64de70d25af868a91edb94c186c)
1 /*
2  * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <stdbool.h>
9 
10 #include <arch_helpers.h>
11 #include <common/debug.h>
12 #include <lib/el3_runtime/cpu_data.h>
13 #include <lib/psci/psci.h>
14 #include <plat/common/platform.h>
15 
16 #include <ti_sci_protocol.h>
17 #include <k3_gicv3.h>
18 #include <ti_sci.h>
19 
20 uintptr_t k3_sec_entrypoint;
21 
22 static void k3_cpu_standby(plat_local_state_t cpu_state)
23 {
24 	unsigned int scr;
25 
26 	scr = read_scr_el3();
27 	/* Enable the Non secure interrupt to wake the CPU */
28 	write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
29 	isb();
30 	/* dsb is good practice before using wfi to enter low power states */
31 	dsb();
32 	/* Enter standby state */
33 	wfi();
34 	/* Restore SCR */
35 	write_scr_el3(scr);
36 }
37 
38 static int k3_pwr_domain_on(u_register_t mpidr)
39 {
40 	int core_id, proc, device, ret;
41 
42 	core_id = plat_core_pos_by_mpidr(mpidr);
43 	if (core_id < 0) {
44 		ERROR("Could not get target core id: %d\n", core_id);
45 		return PSCI_E_INTERN_FAIL;
46 	}
47 
48 	proc = PLAT_PROC_START_ID + core_id;
49 	device = PLAT_PROC_DEVICE_START_ID + core_id;
50 
51 	ret = ti_sci_proc_request(proc);
52 	if (ret) {
53 		ERROR("Request for processor failed: %d\n", ret);
54 		return PSCI_E_INTERN_FAIL;
55 	}
56 
57 	ret = ti_sci_proc_set_boot_cfg(proc, k3_sec_entrypoint, 0, 0);
58 	if (ret) {
59 		ERROR("Request to set core boot address failed: %d\n", ret);
60 		return PSCI_E_INTERN_FAIL;
61 	}
62 
63 	ret = ti_sci_device_get(device);
64 	if (ret) {
65 		ERROR("Request to start core failed: %d\n", ret);
66 		return PSCI_E_INTERN_FAIL;
67 	}
68 
69 	return PSCI_E_SUCCESS;
70 }
71 
72 void k3_pwr_domain_off(const psci_power_state_t *target_state)
73 {
74 	int core_id, proc, device, ret;
75 
76 	/* Prevent interrupts from spuriously waking up this cpu */
77 	k3_gic_cpuif_disable();
78 
79 	core_id = plat_my_core_pos();
80 	proc = PLAT_PROC_START_ID + core_id;
81 	device = PLAT_PROC_DEVICE_START_ID + core_id;
82 
83 	/* Start by sending wait for WFI command */
84 	ret = ti_sci_proc_wait_boot_status_no_wait(proc,
85 			/*
86 			 * Wait maximum time to give us the best chance to get
87 			 * to WFI before this command timeouts
88 			 */
89 			UINT8_MAX, 100, UINT8_MAX, UINT8_MAX,
90 			/* Wait for WFI */
91 			PROC_BOOT_STATUS_FLAG_ARMV8_WFI, 0, 0, 0);
92 	if (ret) {
93 		ERROR("Sending wait for WFI failed (%d)\n", ret);
94 		return;
95 	}
96 
97 	/* Now queue up the core shutdown request */
98 	ret = ti_sci_device_put_no_wait(device);
99 	if (ret) {
100 		ERROR("Sending core shutdown message failed (%d)\n", ret);
101 		return;
102 	}
103 }
104 
105 void k3_pwr_domain_on_finish(const psci_power_state_t *target_state)
106 {
107 	/* TODO: Indicate to System firmware about completion */
108 
109 	k3_gic_pcpu_init();
110 	k3_gic_cpuif_enable();
111 }
112 
113 static void __dead2 k3_system_reset(void)
114 {
115 	/* Send the system reset request to system firmware */
116 	ti_sci_core_reboot();
117 
118 	while (true)
119 		wfi();
120 }
121 
122 static int k3_validate_power_state(unsigned int power_state,
123 				   psci_power_state_t *req_state)
124 {
125 	/* TODO: perform the proper validation */
126 
127 	return PSCI_E_SUCCESS;
128 }
129 
130 static int k3_validate_ns_entrypoint(uintptr_t entrypoint)
131 {
132 	/* TODO: perform the proper validation */
133 
134 	return PSCI_E_SUCCESS;
135 }
136 
137 static const plat_psci_ops_t k3_plat_psci_ops = {
138 	.cpu_standby = k3_cpu_standby,
139 	.pwr_domain_on = k3_pwr_domain_on,
140 	.pwr_domain_off = k3_pwr_domain_off,
141 	.pwr_domain_on_finish = k3_pwr_domain_on_finish,
142 	.system_reset = k3_system_reset,
143 	.validate_power_state = k3_validate_power_state,
144 	.validate_ns_entrypoint = k3_validate_ns_entrypoint
145 };
146 
147 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
148 			const plat_psci_ops_t **psci_ops)
149 {
150 	k3_sec_entrypoint = sec_entrypoint;
151 
152 	*psci_ops = &k3_plat_psci_ops;
153 
154 	return 0;
155 }
156