2 * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
4 * SPDX-License-Identifier: BSD-3-Clause
7 #include <arch_helpers.h>
10 #include <delay_timer.h>
14 #include <platform_def.h>
17 #include <tegra_def.h>
18 #include <tegra_private.h>
21 * Register used to clear CPU reset signals. Each CPU has two reset
22 * signals: CPU reset (3:0) and Core reset (19:16).
24 #define CPU_CMPLX_RESET_CLR 0x454
25 #define CPU_CORE_RESET_MASK 0x10001
27 /* Clock and Reset controller registers for system clock's settings */
28 #define SCLK_RATE 0x30
29 #define SCLK_BURST_POLICY 0x28
30 #define SCLK_BURST_POLICY_DEFAULT 0x10000000
32 static int cpu_powergate_mask
[PLATFORM_MAX_CPUS_PER_CLUSTER
];
34 int32_t tegra_soc_validate_power_state(unsigned int power_state
,
35 psci_power_state_t
*req_state
)
37 int state_id
= psci_get_pstate_id(power_state
);
39 /* Sanity check the requested state id */
41 case PSTATE_ID_CORE_POWERDN
:
43 * Core powerdown request only for afflvl 0
45 req_state
->pwr_domain_state
[MPIDR_AFFLVL0
] = state_id
& 0xff;
49 case PSTATE_ID_CLUSTER_IDLE
:
50 case PSTATE_ID_CLUSTER_POWERDN
:
52 * Cluster powerdown/idle request only for afflvl 1
54 req_state
->pwr_domain_state
[MPIDR_AFFLVL1
] = state_id
;
55 req_state
->pwr_domain_state
[MPIDR_AFFLVL0
] = state_id
;
59 case PSTATE_ID_SOC_POWERDN
:
61 * System powerdown request only for afflvl 2
63 for (uint32_t i
= MPIDR_AFFLVL0
; i
< PLAT_MAX_PWR_LVL
; i
++)
64 req_state
->pwr_domain_state
[i
] = PLAT_MAX_OFF_STATE
;
66 req_state
->pwr_domain_state
[PLAT_MAX_PWR_LVL
] =
67 PLAT_SYS_SUSPEND_STATE_ID
;
72 ERROR("%s: unsupported state id (%d)\n", __func__
, state_id
);
73 return PSCI_E_INVALID_PARAMS
;
76 return PSCI_E_SUCCESS
;
79 /*******************************************************************************
80 * Platform handler to calculate the proper target power level at the
81 * specified affinity level
82 ******************************************************************************/
83 plat_local_state_t
tegra_soc_get_target_pwr_state(unsigned int lvl
,
84 const plat_local_state_t
*states
,
87 plat_local_state_t target
= *states
;
88 int cpu
= plat_my_core_pos();
89 int core_pos
= read_mpidr() & MPIDR_CPU_MASK
;
91 /* get the power state at this level */
92 if (lvl
== MPIDR_AFFLVL1
)
93 target
= *(states
+ core_pos
);
94 if (lvl
== MPIDR_AFFLVL2
)
95 target
= *(states
+ cpu
);
97 /* Cluster idle/power-down */
98 if ((lvl
== MPIDR_AFFLVL1
) && ((target
== PSTATE_ID_CLUSTER_IDLE
) ||
99 (target
== PSTATE_ID_CLUSTER_POWERDN
))) {
104 if (((lvl
== MPIDR_AFFLVL2
) || (lvl
== MPIDR_AFFLVL1
)) &&
105 (target
== PSTATE_ID_SOC_POWERDN
))
106 return PSTATE_ID_SOC_POWERDN
;
109 return PSCI_LOCAL_STATE_RUN
;
112 int tegra_soc_pwr_domain_suspend(const psci_power_state_t
*target_state
)
114 u_register_t mpidr
= read_mpidr();
115 const plat_local_state_t
*pwr_domain_state
=
116 target_state
->pwr_domain_state
;
117 unsigned int stateid_afflvl2
= pwr_domain_state
[MPIDR_AFFLVL2
];
118 unsigned int stateid_afflvl1
= pwr_domain_state
[MPIDR_AFFLVL1
];
119 unsigned int stateid_afflvl0
= pwr_domain_state
[MPIDR_AFFLVL0
];
121 if (stateid_afflvl2
== PSTATE_ID_SOC_POWERDN
) {
123 assert((stateid_afflvl0
== PLAT_MAX_OFF_STATE
) ||
124 (stateid_afflvl0
== PSTATE_ID_SOC_POWERDN
));
125 assert((stateid_afflvl1
== PLAT_MAX_OFF_STATE
) ||
126 (stateid_afflvl1
== PSTATE_ID_SOC_POWERDN
));
128 /* suspend the entire soc */
129 tegra_fc_soc_powerdn(mpidr
);
131 } else if (stateid_afflvl1
== PSTATE_ID_CLUSTER_IDLE
) {
133 assert(stateid_afflvl0
== PSTATE_ID_CLUSTER_IDLE
);
135 /* Prepare for cluster idle */
136 tegra_fc_cluster_idle(mpidr
);
138 } else if (stateid_afflvl1
== PSTATE_ID_CLUSTER_POWERDN
) {
140 assert(stateid_afflvl0
== PSTATE_ID_CLUSTER_POWERDN
);
142 /* Prepare for cluster powerdn */
143 tegra_fc_cluster_powerdn(mpidr
);
145 } else if (stateid_afflvl0
== PSTATE_ID_CORE_POWERDN
) {
147 /* Prepare for cpu powerdn */
148 tegra_fc_cpu_powerdn(mpidr
);
151 ERROR("%s: Unknown state id\n", __func__
);
152 return PSCI_E_NOT_SUPPORTED
;
155 return PSCI_E_SUCCESS
;
158 int tegra_soc_pwr_domain_on_finish(const psci_power_state_t
*target_state
)
163 * Check if we are exiting from SOC_POWERDN.
165 if (target_state
->pwr_domain_state
[PLAT_MAX_PWR_LVL
] ==
166 PLAT_SYS_SUSPEND_STATE_ID
) {
169 * Lock scratch registers which hold the CPU vectors
171 tegra_pmc_lock_cpu_vectors();
174 * Enable WRAP to INCR burst type conversions for
175 * incoming requests on the AXI slave ports.
177 val
= mmio_read_32(TEGRA_MSELECT_BASE
+ MSELECT_CONFIG
);
178 val
&= ~ENABLE_UNSUP_TX_ERRORS
;
179 val
|= ENABLE_WRAP_TO_INCR_BURSTS
;
180 mmio_write_32(TEGRA_MSELECT_BASE
+ MSELECT_CONFIG
, val
);
183 * Restore Boot and Power Management Processor (BPMP) reset
184 * address and reset it.
186 tegra_fc_reset_bpmp();
190 * T210 has a dedicated ARMv7 boot and power mgmt processor, BPMP. It's
191 * used for power management and boot purposes. Inform the BPMP that
192 * we have completed the cluster power up.
194 tegra_fc_lock_active_cluster();
196 return PSCI_E_SUCCESS
;
199 int tegra_soc_pwr_domain_on(u_register_t mpidr
)
201 int cpu
= mpidr
& MPIDR_CPU_MASK
;
202 uint32_t mask
= CPU_CORE_RESET_MASK
<< cpu
;
204 /* Deassert CPU reset signals */
205 mmio_write_32(TEGRA_CAR_RESET_BASE
+ CPU_CMPLX_RESET_CLR
, mask
);
207 /* Turn on CPU using flow controller or PMC */
208 if (cpu_powergate_mask
[cpu
] == 0) {
209 tegra_pmc_cpu_on(cpu
);
210 cpu_powergate_mask
[cpu
] = 1;
212 tegra_fc_cpu_on(cpu
);
215 return PSCI_E_SUCCESS
;
218 int tegra_soc_pwr_domain_off(const psci_power_state_t
*target_state
)
220 tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK
);
221 return PSCI_E_SUCCESS
;
224 int tegra_soc_prepare_system_reset(void)
227 * Set System Clock (SCLK) to POR default so that the clock source
228 * for the PMC APB clock would not be changed due to system reset.
230 mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE
+ SCLK_BURST_POLICY
,
231 SCLK_BURST_POLICY_DEFAULT
);
232 mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE
+ SCLK_RATE
, 0);
234 /* Wait 1 ms to make sure clock source/device logic is stabilized. */
237 return PSCI_E_SUCCESS
;