1 /* 2 * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <errno.h> 8 9 #include <arch_helpers.h> 10 #include <common/bl_common.h> 11 #include <common/debug.h> 12 #include <drivers/arm/cci.h> 13 #include <drivers/arm/gicv2.h> 14 #include <lib/bakery_lock.h> 15 #include <lib/mmio.h> 16 #include <lib/psci/psci.h> 17 #include <plat/common/platform.h> 18 19 #include "iic_dvfs.h" 20 #include "platform_def.h" 21 #include "pwrc.h" 22 #include "rcar_def.h" 23 #include "rcar_private.h" 24 #include "ulcb_cpld.h" 25 26 #define DVFS_SET_VID_0V (0x00) 27 #define P_ALL_OFF (0x80) 28 #define KEEPON_DDR1C (0x08) 29 #define KEEPON_DDR0C (0x04) 30 #define KEEPON_DDR1 (0x02) 31 #define KEEPON_DDR0 (0x01) 32 33 #define SYSTEM_PWR_STATE(s) ((s)->pwr_domain_state[PLAT_MAX_PWR_LVL]) 34 #define CLUSTER_PWR_STATE(s) ((s)->pwr_domain_state[MPIDR_AFFLVL1]) 35 #define CORE_PWR_STATE(s) ((s)->pwr_domain_state[MPIDR_AFFLVL0]) 36 37 extern void rcar_pwrc_restore_generic_timer(uint64_t *stack); 38 extern void plat_rcar_gic_driver_init(void); 39 extern void plat_rcar_gic_init(void); 40 extern u_register_t rcar_boot_mpidr; 41 42 static uintptr_t rcar_sec_entrypoint; 43 44 static void rcar_program_mailbox(uint64_t mpidr, uint64_t address) 45 { 46 mailbox_t *rcar_mboxes = (mailbox_t *) MBOX_BASE; 47 uint64_t linear_id = plat_core_pos_by_mpidr(mpidr); 48 unsigned long range; 49 50 rcar_mboxes[linear_id].value = address; 51 range = (unsigned long)&rcar_mboxes[linear_id]; 52 53 flush_dcache_range(range, sizeof(range)); 54 } 55 56 static void rcar_cpu_standby(plat_local_state_t cpu_state) 57 { 58 u_register_t scr_el3 = read_scr_el3(); 59 60 write_scr_el3(scr_el3 | SCR_IRQ_BIT); 61 dsb(); 62 wfi(); 63 write_scr_el3(scr_el3); 64 } 65 66 static int rcar_pwr_domain_on(u_register_t mpidr) 67 { 68 rcar_program_mailbox(mpidr, rcar_sec_entrypoint); 69 rcar_pwrc_cpuon(mpidr); 70 71 return PSCI_E_SUCCESS; 72 } 73 74 static void rcar_pwr_domain_on_finish(const psci_power_state_t *target_state) 75 { 76 uint32_t cluster_type = rcar_pwrc_get_cluster(); 77 unsigned long mpidr = read_mpidr_el1(); 78 79 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 80 if (cluster_type == RCAR_CLUSTER_A53A57) 81 plat_cci_enable(); 82 83 rcar_pwrc_disable_interrupt_wakeup(mpidr); 84 rcar_program_mailbox(mpidr, 0); 85 86 gicv2_cpuif_enable(); 87 gicv2_pcpu_distif_init(); 88 } 89 90 static void rcar_pwr_domain_off(const psci_power_state_t *target_state) 91 { 92 #if RCAR_LSI != RCAR_D3 93 uint32_t cluster_type = rcar_pwrc_get_cluster(); 94 #endif 95 unsigned long mpidr = read_mpidr_el1(); 96 97 gicv2_cpuif_disable(); 98 rcar_pwrc_cpuoff(mpidr); 99 100 #if RCAR_LSI != RCAR_D3 101 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { 102 if (cluster_type == RCAR_CLUSTER_A53A57) 103 plat_cci_disable(); 104 105 rcar_pwrc_clusteroff(mpidr); 106 } 107 #endif 108 } 109 110 static void rcar_pwr_domain_suspend(const psci_power_state_t *target_state) 111 { 112 uint32_t cluster_type = rcar_pwrc_get_cluster(); 113 unsigned long mpidr = read_mpidr_el1(); 114 115 if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) 116 return; 117 118 rcar_program_mailbox(mpidr, rcar_sec_entrypoint); 119 rcar_pwrc_enable_interrupt_wakeup(mpidr); 120 gicv2_cpuif_disable(); 121 rcar_pwrc_cpuoff(mpidr); 122 123 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { 124 if (cluster_type == RCAR_CLUSTER_A53A57) 125 plat_cci_disable(); 126 127 rcar_pwrc_clusteroff(mpidr); 128 } 129 130 #if RCAR_SYSTEM_SUSPEND 131 if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 132 rcar_pwrc_suspend_to_ram(); 133 #endif 134 } 135 136 static void rcar_pwr_domain_suspend_finish(const psci_power_state_t 137 *target_state) 138 { 139 uint32_t cluster_type = rcar_pwrc_get_cluster(); 140 141 if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) 142 goto finish; 143 144 plat_rcar_gic_driver_init(); 145 plat_rcar_gic_init(); 146 147 if (cluster_type == RCAR_CLUSTER_A53A57) 148 plat_cci_init(); 149 150 rcar_pwrc_restore_timer_state(); 151 rcar_pwrc_setup(); 152 rcar_pwrc_code_copy_to_system_ram(); 153 154 #if RCAR_SYSTEM_SUSPEND 155 rcar_pwrc_init_suspend_to_ram(); 156 #endif 157 finish: 158 rcar_pwr_domain_on_finish(target_state); 159 } 160 161 static void __dead2 rcar_system_off(void) 162 { 163 #if PMIC_ROHM_BD9571 164 #if PMIC_LEVEL_MODE 165 if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V)) 166 ERROR("BL3-1:Failed the SYSTEM-OFF.\n"); 167 #else 168 if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF)) 169 ERROR("BL3-1:Failed the SYSTEM-RESET.\n"); 170 #endif 171 #else 172 uint64_t cpu = read_mpidr_el1() & 0x0000ffff; 173 int32_t rtn_on; 174 175 rtn_on = rcar_pwrc_cpu_on_check(cpu); 176 177 if (cpu == rcar_boot_mpidr) 178 panic(); 179 180 if (rtn_on) 181 panic(); 182 183 rcar_pwrc_cpuoff(cpu); 184 rcar_pwrc_clusteroff(cpu); 185 186 #endif /* PMIC_ROHM_BD9571 */ 187 wfi(); 188 ERROR("RCAR System Off: operation not handled.\n"); 189 panic(); 190 } 191 192 static void __dead2 rcar_system_reset(void) 193 { 194 #if PMIC_ROHM_BD9571 195 #if PMIC_LEVEL_MODE 196 #if RCAR_SYSTEM_RESET_KEEPON_DDR 197 uint8_t mode; 198 int32_t error; 199 200 error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, KEEP10_MAGIC); 201 if (error) { 202 ERROR("Failed send KEEP10 magic ret=%d\n", error); 203 goto done; 204 } 205 206 error = rcar_iic_dvfs_receive(PMIC, BKUP_MODE_CNT, &mode); 207 if (error) { 208 ERROR("Failed receive BKUP_Mode_Cnt ret=%d\n", error); 209 goto done; 210 } 211 212 mode |= KEEPON_DDR1C | KEEPON_DDR0C | KEEPON_DDR1 | KEEPON_DDR0; 213 error = rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, mode); 214 if (error) { 215 ERROR("Failed send KEEPON_DDRx ret=%d\n", error); 216 goto done; 217 } 218 219 rcar_pwrc_set_suspend_to_ram(); 220 done: 221 #else 222 if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF)) 223 ERROR("BL3-1:Failed the SYSTEM-RESET.\n"); 224 #endif 225 #else 226 #if (RCAR_GEN3_ULCB == 1) 227 rcar_cpld_reset_cpu(); 228 #endif 229 #endif 230 #else 231 rcar_pwrc_system_reset(); 232 #endif 233 wfi(); 234 235 ERROR("RCAR System Reset: operation not handled.\n"); 236 panic(); 237 } 238 239 static int rcar_validate_power_state(unsigned int power_state, 240 psci_power_state_t *req_state) 241 { 242 unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 243 unsigned int pstate = psci_get_pstate_type(power_state); 244 uint32_t i; 245 246 if (pstate == PSTATE_TYPE_STANDBY) { 247 if (pwr_lvl != MPIDR_AFFLVL0) 248 return PSCI_E_INVALID_PARAMS; 249 250 req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE; 251 } else { 252 for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++) 253 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; 254 } 255 256 if (psci_get_pstate_id(power_state)) 257 return PSCI_E_INVALID_PARAMS; 258 259 return PSCI_E_SUCCESS; 260 } 261 262 #if RCAR_SYSTEM_SUSPEND 263 static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state) 264 { 265 unsigned long mpidr = read_mpidr_el1() & 0x0000ffffU; 266 int i; 267 268 if (mpidr != rcar_boot_mpidr) 269 goto deny; 270 271 for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) 272 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; 273 274 return; 275 deny: 276 /* deny system suspend entry */ 277 req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSCI_LOCAL_STATE_RUN; 278 for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) 279 req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE; 280 } 281 #endif 282 283 static const plat_psci_ops_t rcar_plat_psci_ops = { 284 .cpu_standby = rcar_cpu_standby, 285 .pwr_domain_on = rcar_pwr_domain_on, 286 .pwr_domain_off = rcar_pwr_domain_off, 287 .pwr_domain_suspend = rcar_pwr_domain_suspend, 288 .pwr_domain_on_finish = rcar_pwr_domain_on_finish, 289 .pwr_domain_suspend_finish = rcar_pwr_domain_suspend_finish, 290 .system_off = rcar_system_off, 291 .system_reset = rcar_system_reset, 292 .validate_power_state = rcar_validate_power_state, 293 #if RCAR_SYSTEM_SUSPEND 294 .get_sys_suspend_power_state = rcar_get_sys_suspend_power_state, 295 #endif 296 }; 297 298 int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) 299 { 300 *psci_ops = &rcar_plat_psci_ops; 301 rcar_sec_entrypoint = sec_entrypoint; 302 303 #if RCAR_SYSTEM_SUSPEND 304 rcar_pwrc_init_suspend_to_ram(); 305 #endif 306 return 0; 307 } 308 309