1 /* 2 * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <arch_helpers.h> 32 #include <arm_config.h> 33 #include <arm_gic.h> 34 #include <assert.h> 35 #include <debug.h> 36 #include <errno.h> 37 #include <mmio.h> 38 #include <platform.h> 39 #include <plat_arm.h> 40 #include <psci.h> 41 #include <v2m_def.h> 42 #include "drivers/pwrc/fvp_pwrc.h" 43 #include "fvp_def.h" 44 #include "fvp_private.h" 45 46 47 typedef volatile struct mailbox { 48 unsigned long value __aligned(CACHE_WRITEBACK_GRANULE); 49 } mailbox_t; 50 51 /******************************************************************************* 52 * Private FVP function to program the mailbox for a cpu before it is released 53 * from reset. 54 ******************************************************************************/ 55 static void fvp_program_mailbox(uint64_t mpidr, uint64_t address) 56 { 57 uint64_t linear_id; 58 mailbox_t *fvp_mboxes; 59 60 linear_id = platform_get_core_pos(mpidr); 61 fvp_mboxes = (mailbox_t *)MBOX_BASE; 62 fvp_mboxes[linear_id].value = address; 63 flush_dcache_range((unsigned long) &fvp_mboxes[linear_id], 64 sizeof(unsigned long)); 65 } 66 67 /******************************************************************************* 68 * Function which implements the common FVP specific operations to power down a 69 * cpu in response to a CPU_OFF or CPU_SUSPEND request. 70 ******************************************************************************/ 71 static void fvp_cpu_pwrdwn_common(void) 72 { 73 /* Prevent interrupts from spuriously waking up this cpu */ 74 arm_gic_cpuif_deactivate(); 75 76 /* Program the power controller to power off this cpu. */ 77 fvp_pwrc_write_ppoffr(read_mpidr_el1()); 78 } 79 80 /******************************************************************************* 81 * Function which implements the common FVP specific operations to power down a 82 * cluster in response to a CPU_OFF or CPU_SUSPEND request. 83 ******************************************************************************/ 84 static void fvp_cluster_pwrdwn_common(void) 85 { 86 uint64_t mpidr = read_mpidr_el1(); 87 88 /* Disable coherency if this cluster is to be turned off */ 89 fvp_cci_disable(); 90 91 /* Program the power controller to turn the cluster off */ 92 fvp_pwrc_write_pcoffr(mpidr); 93 } 94 95 /******************************************************************************* 96 * FVP handler called when an affinity instance is about to enter standby. 97 ******************************************************************************/ 98 void fvp_affinst_standby(unsigned int power_state) 99 { 100 /* 101 * Enter standby state 102 * dsb is good practice before using wfi to enter low power states 103 */ 104 dsb(); 105 wfi(); 106 } 107 108 /******************************************************************************* 109 * FVP handler called when an affinity instance is about to be turned on. The 110 * level and mpidr determine the affinity instance. 111 ******************************************************************************/ 112 int fvp_affinst_on(unsigned long mpidr, 113 unsigned long sec_entrypoint, 114 unsigned int afflvl, 115 unsigned int state) 116 { 117 int rc = PSCI_E_SUCCESS; 118 unsigned int psysr; 119 120 /* 121 * It's possible to turn on only affinity level 0 i.e. a cpu 122 * on the FVP. Ignore any other affinity level. 123 */ 124 if (afflvl != MPIDR_AFFLVL0) 125 return rc; 126 127 /* 128 * Ensure that we do not cancel an inflight power off request 129 * for the target cpu. That would leave it in a zombie wfi. 130 * Wait for it to power off, program the jump address for the 131 * target cpu and then program the power controller to turn 132 * that cpu on 133 */ 134 do { 135 psysr = fvp_pwrc_read_psysr(mpidr); 136 } while (psysr & PSYSR_AFF_L0); 137 138 fvp_program_mailbox(mpidr, sec_entrypoint); 139 fvp_pwrc_write_pponr(mpidr); 140 141 return rc; 142 } 143 144 /******************************************************************************* 145 * FVP handler called when an affinity instance is about to be turned off. The 146 * level and mpidr determine the affinity instance. The 'state' arg. allows the 147 * platform to decide whether the cluster is being turned off and take apt 148 * actions. 149 * 150 * CAUTION: There is no guarantee that caches will remain turned on across calls 151 * to this function as each affinity level is dealt with. So do not write & read 152 * global variables across calls. It will be wise to do flush a write to the 153 * global to prevent unpredictable results. 154 ******************************************************************************/ 155 void fvp_affinst_off(unsigned int afflvl, 156 unsigned int state) 157 { 158 /* Determine if any platform actions need to be executed */ 159 if (arm_do_affinst_actions(afflvl, state) == -EAGAIN) 160 return; 161 162 /* 163 * If execution reaches this stage then this affinity level will be 164 * suspended. Perform at least the cpu specific actions followed the 165 * cluster specific operations if applicable. 166 */ 167 fvp_cpu_pwrdwn_common(); 168 169 if (afflvl != MPIDR_AFFLVL0) 170 fvp_cluster_pwrdwn_common(); 171 172 } 173 174 /******************************************************************************* 175 * FVP handler called when an affinity instance is about to be suspended. The 176 * level and mpidr determine the affinity instance. The 'state' arg. allows the 177 * platform to decide whether the cluster is being turned off and take apt 178 * actions. 179 * 180 * CAUTION: There is no guarantee that caches will remain turned on across calls 181 * to this function as each affinity level is dealt with. So do not write & read 182 * global variables across calls. It will be wise to do flush a write to the 183 * global to prevent unpredictable results. 184 ******************************************************************************/ 185 void fvp_affinst_suspend(unsigned long sec_entrypoint, 186 unsigned int afflvl, 187 unsigned int state) 188 { 189 unsigned long mpidr; 190 191 /* Determine if any platform actions need to be executed. */ 192 if (arm_do_affinst_actions(afflvl, state) == -EAGAIN) 193 return; 194 195 /* Get the mpidr for this cpu */ 196 mpidr = read_mpidr_el1(); 197 198 /* Program the jump address for the this cpu */ 199 fvp_program_mailbox(mpidr, sec_entrypoint); 200 201 /* Program the power controller to enable wakeup interrupts. */ 202 fvp_pwrc_set_wen(mpidr); 203 204 /* Perform the common cpu specific operations */ 205 fvp_cpu_pwrdwn_common(); 206 207 /* Perform the common cluster specific operations */ 208 if (afflvl != MPIDR_AFFLVL0) 209 fvp_cluster_pwrdwn_common(); 210 } 211 212 /******************************************************************************* 213 * FVP handler called when an affinity instance has just been powered on after 214 * being turned off earlier. The level and mpidr determine the affinity 215 * instance. The 'state' arg. allows the platform to decide whether the cluster 216 * was turned off prior to wakeup and do what's necessary to setup it up 217 * correctly. 218 ******************************************************************************/ 219 void fvp_affinst_on_finish(unsigned int afflvl, 220 unsigned int state) 221 { 222 unsigned long mpidr; 223 224 /* Determine if any platform actions need to be executed. */ 225 if (arm_do_affinst_actions(afflvl, state) == -EAGAIN) 226 return; 227 228 /* Get the mpidr for this cpu */ 229 mpidr = read_mpidr_el1(); 230 231 /* Perform the common cluster specific operations */ 232 if (afflvl != MPIDR_AFFLVL0) { 233 /* 234 * This CPU might have woken up whilst the cluster was 235 * attempting to power down. In this case the FVP power 236 * controller will have a pending cluster power off request 237 * which needs to be cleared by writing to the PPONR register. 238 * This prevents the power controller from interpreting a 239 * subsequent entry of this cpu into a simple wfi as a power 240 * down request. 241 */ 242 fvp_pwrc_write_pponr(mpidr); 243 244 /* Enable coherency if this cluster was off */ 245 fvp_cci_enable(); 246 } 247 248 /* 249 * Clear PWKUPR.WEN bit to ensure interrupts do not interfere 250 * with a cpu power down unless the bit is set again 251 */ 252 fvp_pwrc_clr_wen(mpidr); 253 254 /* Zero the jump address in the mailbox for this cpu */ 255 fvp_program_mailbox(mpidr, 0); 256 257 /* Enable the gic cpu interface */ 258 arm_gic_cpuif_setup(); 259 260 /* TODO: This setup is needed only after a cold boot */ 261 arm_gic_pcpu_distif_setup(); 262 } 263 264 /******************************************************************************* 265 * FVP handler called when an affinity instance has just been powered on after 266 * having been suspended earlier. The level and mpidr determine the affinity 267 * instance. 268 * TODO: At the moment we reuse the on finisher and reinitialize the secure 269 * context. Need to implement a separate suspend finisher. 270 ******************************************************************************/ 271 void fvp_affinst_suspend_finish(unsigned int afflvl, 272 unsigned int state) 273 { 274 fvp_affinst_on_finish(afflvl, state); 275 } 276 277 /******************************************************************************* 278 * FVP handlers to shutdown/reboot the system 279 ******************************************************************************/ 280 static void __dead2 fvp_system_off(void) 281 { 282 /* Write the System Configuration Control Register */ 283 mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL, 284 V2M_CFGCTRL_START | 285 V2M_CFGCTRL_RW | 286 V2M_CFGCTRL_FUNC(V2M_FUNC_SHUTDOWN)); 287 wfi(); 288 ERROR("FVP System Off: operation not handled.\n"); 289 panic(); 290 } 291 292 static void __dead2 fvp_system_reset(void) 293 { 294 /* Write the System Configuration Control Register */ 295 mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL, 296 V2M_CFGCTRL_START | 297 V2M_CFGCTRL_RW | 298 V2M_CFGCTRL_FUNC(V2M_FUNC_REBOOT)); 299 wfi(); 300 ERROR("FVP System Reset: operation not handled.\n"); 301 panic(); 302 } 303 304 /******************************************************************************* 305 * Export the platform handlers to enable psci to invoke them 306 ******************************************************************************/ 307 static const plat_pm_ops_t fvp_plat_pm_ops = { 308 .affinst_standby = fvp_affinst_standby, 309 .affinst_on = fvp_affinst_on, 310 .affinst_off = fvp_affinst_off, 311 .affinst_suspend = fvp_affinst_suspend, 312 .affinst_on_finish = fvp_affinst_on_finish, 313 .affinst_suspend_finish = fvp_affinst_suspend_finish, 314 .system_off = fvp_system_off, 315 .system_reset = fvp_system_reset, 316 .validate_power_state = arm_validate_power_state 317 }; 318 319 /******************************************************************************* 320 * Export the platform specific power ops & initialize the fvp power controller 321 ******************************************************************************/ 322 int platform_setup_pm(const plat_pm_ops_t **plat_ops) 323 { 324 *plat_ops = &fvp_plat_pm_ops; 325 return 0; 326 } 327