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 <arch_helpers.h> 8 #include <assert.h> 9 #include <debug.h> 10 #include <delay_timer.h> 11 #include <flowctrl.h> 12 #include <mmio.h> 13 #include <platform.h> 14 #include <platform_def.h> 15 #include <pmc.h> 16 #include <psci.h> 17 #include <tegra_def.h> 18 #include <tegra_private.h> 19 20 /* 21 * Register used to clear CPU reset signals. Each CPU has two reset 22 * signals: CPU reset (3:0) and Core reset (19:16). 23 */ 24 #define CPU_CMPLX_RESET_CLR 0x454 25 #define CPU_CORE_RESET_MASK 0x10001 26 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 31 32 static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER]; 33 34 int32_t tegra_soc_validate_power_state(unsigned int power_state, 35 psci_power_state_t *req_state) 36 { 37 int state_id = psci_get_pstate_id(power_state); 38 39 /* Sanity check the requested state id */ 40 switch (state_id) { 41 case PSTATE_ID_CORE_POWERDN: 42 /* 43 * Core powerdown request only for afflvl 0 44 */ 45 req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id & 0xff; 46 47 break; 48 49 case PSTATE_ID_CLUSTER_IDLE: 50 case PSTATE_ID_CLUSTER_POWERDN: 51 /* 52 * Cluster powerdown/idle request only for afflvl 1 53 */ 54 req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id; 55 req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id; 56 57 break; 58 59 case PSTATE_ID_SOC_POWERDN: 60 /* 61 * System powerdown request only for afflvl 2 62 */ 63 for (uint32_t i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) 64 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; 65 66 req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = 67 PLAT_SYS_SUSPEND_STATE_ID; 68 69 break; 70 71 default: 72 ERROR("%s: unsupported state id (%d)\n", __func__, state_id); 73 return PSCI_E_INVALID_PARAMS; 74 } 75 76 return PSCI_E_SUCCESS; 77 } 78 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, 85 unsigned int ncpu) 86 { 87 plat_local_state_t target = *states; 88 int cpu = plat_my_core_pos(); 89 int core_pos = read_mpidr() & MPIDR_CPU_MASK; 90 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); 96 97 /* Cluster idle/power-down */ 98 if ((lvl == MPIDR_AFFLVL1) && ((target == PSTATE_ID_CLUSTER_IDLE) || 99 (target == PSTATE_ID_CLUSTER_POWERDN))) { 100 return target; 101 } 102 103 /* System Suspend */ 104 if (((lvl == MPIDR_AFFLVL2) || (lvl == MPIDR_AFFLVL1)) && 105 (target == PSTATE_ID_SOC_POWERDN)) 106 return PSTATE_ID_SOC_POWERDN; 107 108 /* default state */ 109 return PSCI_LOCAL_STATE_RUN; 110 } 111 112 int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) 113 { 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]; 120 121 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { 122 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)); 127 128 /* suspend the entire soc */ 129 tegra_fc_soc_powerdn(mpidr); 130 131 } else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) { 132 133 assert(stateid_afflvl0 == PSTATE_ID_CLUSTER_IDLE); 134 135 /* Prepare for cluster idle */ 136 tegra_fc_cluster_idle(mpidr); 137 138 } else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_POWERDN) { 139 140 assert(stateid_afflvl0 == PSTATE_ID_CLUSTER_POWERDN); 141 142 /* Prepare for cluster powerdn */ 143 tegra_fc_cluster_powerdn(mpidr); 144 145 } else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) { 146 147 /* Prepare for cpu powerdn */ 148 tegra_fc_cpu_powerdn(mpidr); 149 150 } else { 151 ERROR("%s: Unknown state id\n", __func__); 152 return PSCI_E_NOT_SUPPORTED; 153 } 154 155 return PSCI_E_SUCCESS; 156 } 157 158 int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) 159 { 160 uint32_t val; 161 162 /* 163 * Check if we are exiting from SOC_POWERDN. 164 */ 165 if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == 166 PLAT_SYS_SUSPEND_STATE_ID) { 167 168 /* 169 * Lock scratch registers which hold the CPU vectors 170 */ 171 tegra_pmc_lock_cpu_vectors(); 172 173 /* 174 * Enable WRAP to INCR burst type conversions for 175 * incoming requests on the AXI slave ports. 176 */ 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); 181 182 /* 183 * Restore Boot and Power Management Processor (BPMP) reset 184 * address and reset it. 185 */ 186 tegra_fc_reset_bpmp(); 187 } 188 189 /* 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. 193 */ 194 tegra_fc_lock_active_cluster(); 195 196 return PSCI_E_SUCCESS; 197 } 198 199 int tegra_soc_pwr_domain_on(u_register_t mpidr) 200 { 201 int cpu = mpidr & MPIDR_CPU_MASK; 202 uint32_t mask = CPU_CORE_RESET_MASK << cpu; 203 204 /* Deassert CPU reset signals */ 205 mmio_write_32(TEGRA_CAR_RESET_BASE + CPU_CMPLX_RESET_CLR, mask); 206 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; 211 } else { 212 tegra_fc_cpu_on(cpu); 213 } 214 215 return PSCI_E_SUCCESS; 216 } 217 218 int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) 219 { 220 tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK); 221 return PSCI_E_SUCCESS; 222 } 223 224 int tegra_soc_prepare_system_reset(void) 225 { 226 /* 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. 229 */ 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); 233 234 /* Wait 1 ms to make sure clock source/device logic is stabilized. */ 235 mdelay(1); 236 237 return PSCI_E_SUCCESS; 238 } 239