1499c2713SBiju Das /* 2731aa26fSToshiyuki Ogasahara * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved. 3499c2713SBiju Das * 4499c2713SBiju Das * SPDX-License-Identifier: BSD-3-Clause 5499c2713SBiju Das */ 6499c2713SBiju Das 7499c2713SBiju Das #include <errno.h> 8499c2713SBiju Das 9499c2713SBiju Das #include <arch_helpers.h> 10499c2713SBiju Das #include <common/bl_common.h> 11499c2713SBiju Das #include <common/debug.h> 12499c2713SBiju Das #include <drivers/arm/cci.h> 13499c2713SBiju Das #include <drivers/arm/gicv2.h> 14499c2713SBiju Das #include <lib/bakery_lock.h> 15499c2713SBiju Das #include <lib/mmio.h> 16499c2713SBiju Das #include <lib/psci/psci.h> 17499c2713SBiju Das #include <plat/common/platform.h> 18499c2713SBiju Das 19499c2713SBiju Das #include "iic_dvfs.h" 20499c2713SBiju Das #include "platform_def.h" 21499c2713SBiju Das #include "pwrc.h" 22499c2713SBiju Das #include "rcar_def.h" 23499c2713SBiju Das #include "rcar_private.h" 2427bbfca9SBiju Das #if RCAR_GEN3_ULCB 25499c2713SBiju Das #include "ulcb_cpld.h" 2627bbfca9SBiju Das #endif /* RCAR_GEN3_ULCB */ 27499c2713SBiju Das 28499c2713SBiju Das #define DVFS_SET_VID_0V (0x00) 29499c2713SBiju Das #define P_ALL_OFF (0x80) 30499c2713SBiju Das #define KEEPON_DDR1C (0x08) 31499c2713SBiju Das #define KEEPON_DDR0C (0x04) 32499c2713SBiju Das #define KEEPON_DDR1 (0x02) 33499c2713SBiju Das #define KEEPON_DDR0 (0x01) 34499c2713SBiju Das 35499c2713SBiju Das #define SYSTEM_PWR_STATE(s) ((s)->pwr_domain_state[PLAT_MAX_PWR_LVL]) 36499c2713SBiju Das #define CLUSTER_PWR_STATE(s) ((s)->pwr_domain_state[MPIDR_AFFLVL1]) 37499c2713SBiju Das #define CORE_PWR_STATE(s) ((s)->pwr_domain_state[MPIDR_AFFLVL0]) 38499c2713SBiju Das 39499c2713SBiju Das extern void rcar_pwrc_restore_generic_timer(uint64_t *stack); 40499c2713SBiju Das extern void plat_rcar_gic_driver_init(void); 41499c2713SBiju Das extern void plat_rcar_gic_init(void); 42499c2713SBiju Das 43499c2713SBiju Das static uintptr_t rcar_sec_entrypoint; 44499c2713SBiju Das 45*ffb725beSTakuya Sakata static void rcar_program_mailbox(u_register_t mpidr, uintptr_t address) 46499c2713SBiju Das { 47499c2713SBiju Das mailbox_t *rcar_mboxes = (mailbox_t *) MBOX_BASE; 48499c2713SBiju Das uint64_t linear_id = plat_core_pos_by_mpidr(mpidr); 49499c2713SBiju Das unsigned long range; 50499c2713SBiju Das 51499c2713SBiju Das rcar_mboxes[linear_id].value = address; 52499c2713SBiju Das range = (unsigned long)&rcar_mboxes[linear_id]; 53499c2713SBiju Das 54499c2713SBiju Das flush_dcache_range(range, sizeof(range)); 55499c2713SBiju Das } 56499c2713SBiju Das 57499c2713SBiju Das static void rcar_cpu_standby(plat_local_state_t cpu_state) 58499c2713SBiju Das { 59499c2713SBiju Das u_register_t scr_el3 = read_scr_el3(); 60499c2713SBiju Das 61499c2713SBiju Das write_scr_el3(scr_el3 | SCR_IRQ_BIT); 62499c2713SBiju Das dsb(); 63499c2713SBiju Das wfi(); 64499c2713SBiju Das write_scr_el3(scr_el3); 65499c2713SBiju Das } 66499c2713SBiju Das 67499c2713SBiju Das static int rcar_pwr_domain_on(u_register_t mpidr) 68499c2713SBiju Das { 69499c2713SBiju Das rcar_program_mailbox(mpidr, rcar_sec_entrypoint); 70499c2713SBiju Das rcar_pwrc_cpuon(mpidr); 71499c2713SBiju Das 72499c2713SBiju Das return PSCI_E_SUCCESS; 73499c2713SBiju Das } 74499c2713SBiju Das 75499c2713SBiju Das static void rcar_pwr_domain_on_finish(const psci_power_state_t *target_state) 76499c2713SBiju Das { 77499c2713SBiju Das uint32_t cluster_type = rcar_pwrc_get_cluster(); 78*ffb725beSTakuya Sakata u_register_t mpidr = read_mpidr_el1(); 79499c2713SBiju Das 80499c2713SBiju Das if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 81499c2713SBiju Das if (cluster_type == RCAR_CLUSTER_A53A57) 82499c2713SBiju Das plat_cci_enable(); 83499c2713SBiju Das 84499c2713SBiju Das rcar_program_mailbox(mpidr, 0); 85d9912cf3STakuya Sakata rcar_pwrc_enable_interrupt_wakeup(mpidr); 86499c2713SBiju Das 87499c2713SBiju Das gicv2_cpuif_enable(); 88499c2713SBiju Das gicv2_pcpu_distif_init(); 89499c2713SBiju Das } 90499c2713SBiju Das 91499c2713SBiju Das static void rcar_pwr_domain_off(const psci_power_state_t *target_state) 92499c2713SBiju Das { 93499c2713SBiju Das #if RCAR_LSI != RCAR_D3 94499c2713SBiju Das uint32_t cluster_type = rcar_pwrc_get_cluster(); 95499c2713SBiju Das #endif 96*ffb725beSTakuya Sakata u_register_t mpidr = read_mpidr_el1(); 97499c2713SBiju Das 98d9912cf3STakuya Sakata rcar_pwrc_disable_interrupt_wakeup(mpidr); 99499c2713SBiju Das gicv2_cpuif_disable(); 100499c2713SBiju Das rcar_pwrc_cpuoff(mpidr); 101499c2713SBiju Das 102499c2713SBiju Das #if RCAR_LSI != RCAR_D3 103499c2713SBiju Das if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { 104499c2713SBiju Das if (cluster_type == RCAR_CLUSTER_A53A57) 105499c2713SBiju Das plat_cci_disable(); 106499c2713SBiju Das 107499c2713SBiju Das rcar_pwrc_clusteroff(mpidr); 108499c2713SBiju Das } 109499c2713SBiju Das #endif 110499c2713SBiju Das } 111499c2713SBiju Das 112499c2713SBiju Das static void rcar_pwr_domain_suspend(const psci_power_state_t *target_state) 113499c2713SBiju Das { 114499c2713SBiju Das uint32_t cluster_type = rcar_pwrc_get_cluster(); 115*ffb725beSTakuya Sakata u_register_t mpidr = read_mpidr_el1(); 116499c2713SBiju Das 117499c2713SBiju Das if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) 118499c2713SBiju Das return; 119499c2713SBiju Das 120499c2713SBiju Das rcar_program_mailbox(mpidr, rcar_sec_entrypoint); 121499c2713SBiju Das rcar_pwrc_enable_interrupt_wakeup(mpidr); 122499c2713SBiju Das gicv2_cpuif_disable(); 123499c2713SBiju Das rcar_pwrc_cpuoff(mpidr); 124499c2713SBiju Das 125499c2713SBiju Das if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { 126499c2713SBiju Das if (cluster_type == RCAR_CLUSTER_A53A57) 127499c2713SBiju Das plat_cci_disable(); 128499c2713SBiju Das 129499c2713SBiju Das rcar_pwrc_clusteroff(mpidr); 130499c2713SBiju Das } 131499c2713SBiju Das } 132499c2713SBiju Das 133499c2713SBiju Das static void rcar_pwr_domain_suspend_finish(const psci_power_state_t 134499c2713SBiju Das *target_state) 135499c2713SBiju Das { 136499c2713SBiju Das uint32_t cluster_type = rcar_pwrc_get_cluster(); 137499c2713SBiju Das 138499c2713SBiju Das if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) 139499c2713SBiju Das goto finish; 140499c2713SBiju Das 141499c2713SBiju Das plat_rcar_gic_driver_init(); 142499c2713SBiju Das plat_rcar_gic_init(); 143499c2713SBiju Das 144499c2713SBiju Das if (cluster_type == RCAR_CLUSTER_A53A57) 145499c2713SBiju Das plat_cci_init(); 146499c2713SBiju Das 147499c2713SBiju Das rcar_pwrc_restore_timer_state(); 148499c2713SBiju Das rcar_pwrc_setup(); 149499c2713SBiju Das rcar_pwrc_code_copy_to_system_ram(); 150499c2713SBiju Das 151499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND 152499c2713SBiju Das rcar_pwrc_init_suspend_to_ram(); 153499c2713SBiju Das #endif 154499c2713SBiju Das finish: 155499c2713SBiju Das rcar_pwr_domain_on_finish(target_state); 156499c2713SBiju Das } 157499c2713SBiju Das 158731aa26fSToshiyuki Ogasahara static void __dead2 rcar_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state) 159731aa26fSToshiyuki Ogasahara { 160731aa26fSToshiyuki Ogasahara #if RCAR_SYSTEM_SUSPEND 161731aa26fSToshiyuki Ogasahara if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 162731aa26fSToshiyuki Ogasahara rcar_pwrc_suspend_to_ram(); 163731aa26fSToshiyuki Ogasahara #endif 164731aa26fSToshiyuki Ogasahara wfi(); 165731aa26fSToshiyuki Ogasahara 166731aa26fSToshiyuki Ogasahara ERROR("RCAR Power Down: operation not handled.\n"); 167731aa26fSToshiyuki Ogasahara panic(); 168731aa26fSToshiyuki Ogasahara } 169731aa26fSToshiyuki Ogasahara 170499c2713SBiju Das static void __dead2 rcar_system_off(void) 171499c2713SBiju Das { 172499c2713SBiju Das #if PMIC_ROHM_BD9571 173499c2713SBiju Das #if PMIC_LEVEL_MODE 174499c2713SBiju Das if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V)) 175499c2713SBiju Das ERROR("BL3-1:Failed the SYSTEM-OFF.\n"); 176499c2713SBiju Das #else 177499c2713SBiju Das if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF)) 178499c2713SBiju Das ERROR("BL3-1:Failed the SYSTEM-RESET.\n"); 179499c2713SBiju Das #endif 180499c2713SBiju Das #else 181*ffb725beSTakuya Sakata u_register_t cpu = read_mpidr_el1() & 0x0000ffffU; 182499c2713SBiju Das int32_t rtn_on; 183499c2713SBiju Das 184499c2713SBiju Das rtn_on = rcar_pwrc_cpu_on_check(cpu); 185499c2713SBiju Das 186499c2713SBiju Das if (cpu == rcar_boot_mpidr) 187499c2713SBiju Das panic(); 188499c2713SBiju Das 189499c2713SBiju Das if (rtn_on) 190499c2713SBiju Das panic(); 191499c2713SBiju Das 192499c2713SBiju Das rcar_pwrc_cpuoff(cpu); 193499c2713SBiju Das rcar_pwrc_clusteroff(cpu); 194499c2713SBiju Das 195499c2713SBiju Das #endif /* PMIC_ROHM_BD9571 */ 196499c2713SBiju Das wfi(); 197499c2713SBiju Das ERROR("RCAR System Off: operation not handled.\n"); 198499c2713SBiju Das panic(); 199499c2713SBiju Das } 200499c2713SBiju Das 201499c2713SBiju Das static void __dead2 rcar_system_reset(void) 202499c2713SBiju Das { 203499c2713SBiju Das #if PMIC_ROHM_BD9571 204499c2713SBiju Das #if PMIC_LEVEL_MODE 205499c2713SBiju Das #if RCAR_SYSTEM_RESET_KEEPON_DDR 206499c2713SBiju Das uint8_t mode; 207499c2713SBiju Das int32_t error; 208499c2713SBiju Das 209499c2713SBiju Das error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, KEEP10_MAGIC); 210499c2713SBiju Das if (error) { 211499c2713SBiju Das ERROR("Failed send KEEP10 magic ret=%d\n", error); 212499c2713SBiju Das goto done; 213499c2713SBiju Das } 214499c2713SBiju Das 215499c2713SBiju Das error = rcar_iic_dvfs_receive(PMIC, BKUP_MODE_CNT, &mode); 216499c2713SBiju Das if (error) { 217499c2713SBiju Das ERROR("Failed receive BKUP_Mode_Cnt ret=%d\n", error); 218499c2713SBiju Das goto done; 219499c2713SBiju Das } 220499c2713SBiju Das 221499c2713SBiju Das mode |= KEEPON_DDR1C | KEEPON_DDR0C | KEEPON_DDR1 | KEEPON_DDR0; 222499c2713SBiju Das error = rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, mode); 223499c2713SBiju Das if (error) { 224499c2713SBiju Das ERROR("Failed send KEEPON_DDRx ret=%d\n", error); 225499c2713SBiju Das goto done; 226499c2713SBiju Das } 227499c2713SBiju Das 228499c2713SBiju Das rcar_pwrc_set_suspend_to_ram(); 229499c2713SBiju Das done: 230499c2713SBiju Das #else 231499c2713SBiju Das if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF)) 232499c2713SBiju Das ERROR("BL3-1:Failed the SYSTEM-RESET.\n"); 233499c2713SBiju Das #endif 234499c2713SBiju Das #else 235499c2713SBiju Das #if (RCAR_GEN3_ULCB == 1) 236499c2713SBiju Das rcar_cpld_reset_cpu(); 237499c2713SBiju Das #endif 238499c2713SBiju Das #endif 239499c2713SBiju Das #else 240499c2713SBiju Das rcar_pwrc_system_reset(); 241499c2713SBiju Das #endif 242499c2713SBiju Das wfi(); 243499c2713SBiju Das 244499c2713SBiju Das ERROR("RCAR System Reset: operation not handled.\n"); 245499c2713SBiju Das panic(); 246499c2713SBiju Das } 247499c2713SBiju Das 248499c2713SBiju Das static int rcar_validate_power_state(unsigned int power_state, 249499c2713SBiju Das psci_power_state_t *req_state) 250499c2713SBiju Das { 251499c2713SBiju Das unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 252499c2713SBiju Das unsigned int pstate = psci_get_pstate_type(power_state); 253499c2713SBiju Das uint32_t i; 254499c2713SBiju Das 255499c2713SBiju Das if (pstate == PSTATE_TYPE_STANDBY) { 256499c2713SBiju Das if (pwr_lvl != MPIDR_AFFLVL0) 257499c2713SBiju Das return PSCI_E_INVALID_PARAMS; 258499c2713SBiju Das 259499c2713SBiju Das req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE; 260499c2713SBiju Das } else { 261499c2713SBiju Das for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++) 262499c2713SBiju Das req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; 263499c2713SBiju Das } 264499c2713SBiju Das 265499c2713SBiju Das if (psci_get_pstate_id(power_state)) 266499c2713SBiju Das return PSCI_E_INVALID_PARAMS; 267499c2713SBiju Das 268499c2713SBiju Das return PSCI_E_SUCCESS; 269499c2713SBiju Das } 270499c2713SBiju Das 271499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND 272499c2713SBiju Das static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state) 273499c2713SBiju Das { 274*ffb725beSTakuya Sakata u_register_t mpidr = read_mpidr_el1() & 0x0000ffffU; 275499c2713SBiju Das int i; 276499c2713SBiju Das 277499c2713SBiju Das if (mpidr != rcar_boot_mpidr) 278499c2713SBiju Das goto deny; 279499c2713SBiju Das 280499c2713SBiju Das for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) 281499c2713SBiju Das req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; 282499c2713SBiju Das 283499c2713SBiju Das return; 284499c2713SBiju Das deny: 285499c2713SBiju Das /* deny system suspend entry */ 286499c2713SBiju Das req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSCI_LOCAL_STATE_RUN; 287499c2713SBiju Das for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) 288499c2713SBiju Das req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE; 289499c2713SBiju Das } 290499c2713SBiju Das #endif 291499c2713SBiju Das 292499c2713SBiju Das static const plat_psci_ops_t rcar_plat_psci_ops = { 293499c2713SBiju Das .cpu_standby = rcar_cpu_standby, 294499c2713SBiju Das .pwr_domain_on = rcar_pwr_domain_on, 295499c2713SBiju Das .pwr_domain_off = rcar_pwr_domain_off, 296499c2713SBiju Das .pwr_domain_suspend = rcar_pwr_domain_suspend, 297499c2713SBiju Das .pwr_domain_on_finish = rcar_pwr_domain_on_finish, 298499c2713SBiju Das .pwr_domain_suspend_finish = rcar_pwr_domain_suspend_finish, 299499c2713SBiju Das .system_off = rcar_system_off, 300499c2713SBiju Das .system_reset = rcar_system_reset, 301499c2713SBiju Das .validate_power_state = rcar_validate_power_state, 302731aa26fSToshiyuki Ogasahara .pwr_domain_pwr_down_wfi = rcar_pwr_domain_pwr_down_wfi, 303499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND 304499c2713SBiju Das .get_sys_suspend_power_state = rcar_get_sys_suspend_power_state, 305499c2713SBiju Das #endif 306499c2713SBiju Das }; 307499c2713SBiju Das 308499c2713SBiju Das int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) 309499c2713SBiju Das { 310499c2713SBiju Das *psci_ops = &rcar_plat_psci_ops; 311499c2713SBiju Das rcar_sec_entrypoint = sec_entrypoint; 312499c2713SBiju Das 313499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND 314499c2713SBiju Das rcar_pwrc_init_suspend_to_ram(); 315499c2713SBiju Das #endif 316499c2713SBiju Das return 0; 317499c2713SBiju Das } 318499c2713SBiju Das 319