xref: /rk3399_ARM-atf/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c (revision 09d40e0e08283a249e7dce0e106c07c5141f9b7e)
1 /*
2  * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 
9 #include <platform_def.h>
10 
11 #include <arch_helpers.h>
12 #include <common/debug.h>
13 #include <drivers/delay_timer.h>
14 #include <lib/mmio.h>
15 #include <lib/psci/psci.h>
16 #include <plat/common/platform.h>
17 
18 #include <flowctrl.h>
19 #include <pmc.h>
20 #include <tegra_def.h>
21 #include <tegra_private.h>
22 
23 /*
24  * Register used to clear CPU reset signals. Each CPU has two reset
25  * signals: CPU reset (3:0) and Core reset (19:16).
26  */
27 #define CPU_CMPLX_RESET_CLR		0x454
28 #define CPU_CORE_RESET_MASK		0x10001
29 
30 /* Clock and Reset controller registers for system clock's settings */
31 #define SCLK_RATE			0x30
32 #define SCLK_BURST_POLICY		0x28
33 #define SCLK_BURST_POLICY_DEFAULT	0x10000000
34 
35 static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
36 
37 int32_t tegra_soc_validate_power_state(unsigned int power_state,
38 					psci_power_state_t *req_state)
39 {
40 	int state_id = psci_get_pstate_id(power_state);
41 
42 	/* Sanity check the requested state id */
43 	switch (state_id) {
44 	case PSTATE_ID_CORE_POWERDN:
45 		/*
46 		 * Core powerdown request only for afflvl 0
47 		 */
48 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id & 0xff;
49 
50 		break;
51 
52 	case PSTATE_ID_CLUSTER_IDLE:
53 	case PSTATE_ID_CLUSTER_POWERDN:
54 		/*
55 		 * Cluster powerdown/idle request only for afflvl 1
56 		 */
57 		req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
58 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id;
59 
60 		break;
61 
62 	case PSTATE_ID_SOC_POWERDN:
63 		/*
64 		 * System powerdown request only for afflvl 2
65 		 */
66 		for (uint32_t i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
67 			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
68 
69 		req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
70 			PLAT_SYS_SUSPEND_STATE_ID;
71 
72 		break;
73 
74 	default:
75 		ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
76 		return PSCI_E_INVALID_PARAMS;
77 	}
78 
79 	return PSCI_E_SUCCESS;
80 }
81 
82 /*******************************************************************************
83  * Platform handler to calculate the proper target power level at the
84  * specified affinity level
85  ******************************************************************************/
86 plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl,
87 					     const plat_local_state_t *states,
88 					     unsigned int ncpu)
89 {
90 	plat_local_state_t target = *states;
91 	int cpu = plat_my_core_pos();
92 	int core_pos = read_mpidr() & MPIDR_CPU_MASK;
93 
94 	/* get the power state at this level */
95 	if (lvl == MPIDR_AFFLVL1)
96 		target = *(states + core_pos);
97 	if (lvl == MPIDR_AFFLVL2)
98 		target = *(states + cpu);
99 
100 	/* Cluster idle/power-down */
101 	if ((lvl == MPIDR_AFFLVL1) && ((target == PSTATE_ID_CLUSTER_IDLE) ||
102 	    (target == PSTATE_ID_CLUSTER_POWERDN))) {
103 		return target;
104 	}
105 
106 	/* System Suspend */
107 	if (((lvl == MPIDR_AFFLVL2) || (lvl == MPIDR_AFFLVL1)) &&
108 	    (target == PSTATE_ID_SOC_POWERDN))
109 		return PSTATE_ID_SOC_POWERDN;
110 
111 	/* default state */
112 	return PSCI_LOCAL_STATE_RUN;
113 }
114 
115 int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
116 {
117 	u_register_t mpidr = read_mpidr();
118 	const plat_local_state_t *pwr_domain_state =
119 		target_state->pwr_domain_state;
120 	unsigned int stateid_afflvl2 = pwr_domain_state[MPIDR_AFFLVL2];
121 	unsigned int stateid_afflvl1 = pwr_domain_state[MPIDR_AFFLVL1];
122 	unsigned int stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0];
123 
124 	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
125 
126 		assert((stateid_afflvl0 == PLAT_MAX_OFF_STATE) ||
127 		       (stateid_afflvl0 == PSTATE_ID_SOC_POWERDN));
128 		assert((stateid_afflvl1 == PLAT_MAX_OFF_STATE) ||
129 		       (stateid_afflvl1 == PSTATE_ID_SOC_POWERDN));
130 
131 		/* suspend the entire soc */
132 		tegra_fc_soc_powerdn(mpidr);
133 
134 	} else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) {
135 
136 		assert(stateid_afflvl0 == PSTATE_ID_CLUSTER_IDLE);
137 
138 		/* Prepare for cluster idle */
139 		tegra_fc_cluster_idle(mpidr);
140 
141 	} else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_POWERDN) {
142 
143 		assert(stateid_afflvl0 == PSTATE_ID_CLUSTER_POWERDN);
144 
145 		/* Prepare for cluster powerdn */
146 		tegra_fc_cluster_powerdn(mpidr);
147 
148 	} else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) {
149 
150 		/* Prepare for cpu powerdn */
151 		tegra_fc_cpu_powerdn(mpidr);
152 
153 	} else {
154 		ERROR("%s: Unknown state id\n", __func__);
155 		return PSCI_E_NOT_SUPPORTED;
156 	}
157 
158 	return PSCI_E_SUCCESS;
159 }
160 
161 int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
162 {
163 	uint32_t val;
164 
165 	/*
166 	 * Check if we are exiting from SOC_POWERDN.
167 	 */
168 	if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
169 			PLAT_SYS_SUSPEND_STATE_ID) {
170 
171 		/*
172 		 * Lock scratch registers which hold the CPU vectors
173 		 */
174 		tegra_pmc_lock_cpu_vectors();
175 
176 		/*
177 		 * Enable WRAP to INCR burst type conversions for
178 		 * incoming requests on the AXI slave ports.
179 		 */
180 		val = mmio_read_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG);
181 		val &= ~ENABLE_UNSUP_TX_ERRORS;
182 		val |= ENABLE_WRAP_TO_INCR_BURSTS;
183 		mmio_write_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG, val);
184 
185 		/*
186 		 * Restore Boot and Power Management Processor (BPMP) reset
187 		 * address and reset it.
188 		 */
189 		tegra_fc_reset_bpmp();
190 	}
191 
192 	/*
193 	 * T210 has a dedicated ARMv7 boot and power mgmt processor, BPMP. It's
194 	 * used for power management and boot purposes. Inform the BPMP that
195 	 * we have completed the cluster power up.
196 	 */
197 	tegra_fc_lock_active_cluster();
198 
199 	return PSCI_E_SUCCESS;
200 }
201 
202 int tegra_soc_pwr_domain_on(u_register_t mpidr)
203 {
204 	int cpu = mpidr & MPIDR_CPU_MASK;
205 	uint32_t mask = CPU_CORE_RESET_MASK << cpu;
206 
207 	/* Deassert CPU reset signals */
208 	mmio_write_32(TEGRA_CAR_RESET_BASE + CPU_CMPLX_RESET_CLR, mask);
209 
210 	/* Turn on CPU using flow controller or PMC */
211 	if (cpu_powergate_mask[cpu] == 0) {
212 		tegra_pmc_cpu_on(cpu);
213 		cpu_powergate_mask[cpu] = 1;
214 	} else {
215 		tegra_fc_cpu_on(cpu);
216 	}
217 
218 	return PSCI_E_SUCCESS;
219 }
220 
221 int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
222 {
223 	tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
224 	return PSCI_E_SUCCESS;
225 }
226 
227 int tegra_soc_prepare_system_reset(void)
228 {
229 	/*
230 	 * Set System Clock (SCLK) to POR default so that the clock source
231 	 * for the PMC APB clock would not be changed due to system reset.
232 	 */
233 	mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_BURST_POLICY,
234 		       SCLK_BURST_POLICY_DEFAULT);
235 	mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_RATE, 0);
236 
237 	/* Wait 1 ms to make sure clock source/device logic is stabilized. */
238 	mdelay(1);
239 
240 	return PSCI_E_SUCCESS;
241 }
242