1499c2713SBiju Das /* 2499c2713SBiju Das * Copyright (c) 2015-2020, 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" 24*27bbfca9SBiju Das #if RCAR_GEN3_ULCB 25499c2713SBiju Das #include "ulcb_cpld.h" 26*27bbfca9SBiju 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 extern u_register_t rcar_boot_mpidr; 43499c2713SBiju Das 44499c2713SBiju Das static uintptr_t rcar_sec_entrypoint; 45499c2713SBiju Das 46499c2713SBiju Das static void rcar_program_mailbox(uint64_t mpidr, uint64_t address) 47499c2713SBiju Das { 48499c2713SBiju Das mailbox_t *rcar_mboxes = (mailbox_t *) MBOX_BASE; 49499c2713SBiju Das uint64_t linear_id = plat_core_pos_by_mpidr(mpidr); 50499c2713SBiju Das unsigned long range; 51499c2713SBiju Das 52499c2713SBiju Das rcar_mboxes[linear_id].value = address; 53499c2713SBiju Das range = (unsigned long)&rcar_mboxes[linear_id]; 54499c2713SBiju Das 55499c2713SBiju Das flush_dcache_range(range, sizeof(range)); 56499c2713SBiju Das } 57499c2713SBiju Das 58499c2713SBiju Das static void rcar_cpu_standby(plat_local_state_t cpu_state) 59499c2713SBiju Das { 60499c2713SBiju Das u_register_t scr_el3 = read_scr_el3(); 61499c2713SBiju Das 62499c2713SBiju Das write_scr_el3(scr_el3 | SCR_IRQ_BIT); 63499c2713SBiju Das dsb(); 64499c2713SBiju Das wfi(); 65499c2713SBiju Das write_scr_el3(scr_el3); 66499c2713SBiju Das } 67499c2713SBiju Das 68499c2713SBiju Das static int rcar_pwr_domain_on(u_register_t mpidr) 69499c2713SBiju Das { 70499c2713SBiju Das rcar_program_mailbox(mpidr, rcar_sec_entrypoint); 71499c2713SBiju Das rcar_pwrc_cpuon(mpidr); 72499c2713SBiju Das 73499c2713SBiju Das return PSCI_E_SUCCESS; 74499c2713SBiju Das } 75499c2713SBiju Das 76499c2713SBiju Das static void rcar_pwr_domain_on_finish(const psci_power_state_t *target_state) 77499c2713SBiju Das { 78499c2713SBiju Das uint32_t cluster_type = rcar_pwrc_get_cluster(); 79499c2713SBiju Das unsigned long mpidr = read_mpidr_el1(); 80499c2713SBiju Das 81499c2713SBiju Das if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 82499c2713SBiju Das if (cluster_type == RCAR_CLUSTER_A53A57) 83499c2713SBiju Das plat_cci_enable(); 84499c2713SBiju Das 85499c2713SBiju Das rcar_pwrc_disable_interrupt_wakeup(mpidr); 86499c2713SBiju Das rcar_program_mailbox(mpidr, 0); 87499c2713SBiju Das 88499c2713SBiju Das gicv2_cpuif_enable(); 89499c2713SBiju Das gicv2_pcpu_distif_init(); 90499c2713SBiju Das } 91499c2713SBiju Das 92499c2713SBiju Das static void rcar_pwr_domain_off(const psci_power_state_t *target_state) 93499c2713SBiju Das { 94499c2713SBiju Das #if RCAR_LSI != RCAR_D3 95499c2713SBiju Das uint32_t cluster_type = rcar_pwrc_get_cluster(); 96499c2713SBiju Das #endif 97499c2713SBiju Das unsigned long mpidr = read_mpidr_el1(); 98499c2713SBiju Das 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(); 115499c2713SBiju Das unsigned long 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 #if RCAR_SYSTEM_SUSPEND 133499c2713SBiju Das if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 134499c2713SBiju Das rcar_pwrc_suspend_to_ram(); 135499c2713SBiju Das #endif 136499c2713SBiju Das } 137499c2713SBiju Das 138499c2713SBiju Das static void rcar_pwr_domain_suspend_finish(const psci_power_state_t 139499c2713SBiju Das *target_state) 140499c2713SBiju Das { 141499c2713SBiju Das uint32_t cluster_type = rcar_pwrc_get_cluster(); 142499c2713SBiju Das 143499c2713SBiju Das if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) 144499c2713SBiju Das goto finish; 145499c2713SBiju Das 146499c2713SBiju Das plat_rcar_gic_driver_init(); 147499c2713SBiju Das plat_rcar_gic_init(); 148499c2713SBiju Das 149499c2713SBiju Das if (cluster_type == RCAR_CLUSTER_A53A57) 150499c2713SBiju Das plat_cci_init(); 151499c2713SBiju Das 152499c2713SBiju Das rcar_pwrc_restore_timer_state(); 153499c2713SBiju Das rcar_pwrc_setup(); 154499c2713SBiju Das rcar_pwrc_code_copy_to_system_ram(); 155499c2713SBiju Das 156499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND 157499c2713SBiju Das rcar_pwrc_init_suspend_to_ram(); 158499c2713SBiju Das #endif 159499c2713SBiju Das finish: 160499c2713SBiju Das rcar_pwr_domain_on_finish(target_state); 161499c2713SBiju Das } 162499c2713SBiju Das 163499c2713SBiju Das static void __dead2 rcar_system_off(void) 164499c2713SBiju Das { 165499c2713SBiju Das #if PMIC_ROHM_BD9571 166499c2713SBiju Das #if PMIC_LEVEL_MODE 167499c2713SBiju Das if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V)) 168499c2713SBiju Das ERROR("BL3-1:Failed the SYSTEM-OFF.\n"); 169499c2713SBiju Das #else 170499c2713SBiju Das if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF)) 171499c2713SBiju Das ERROR("BL3-1:Failed the SYSTEM-RESET.\n"); 172499c2713SBiju Das #endif 173499c2713SBiju Das #else 174499c2713SBiju Das uint64_t cpu = read_mpidr_el1() & 0x0000ffff; 175499c2713SBiju Das int32_t rtn_on; 176499c2713SBiju Das 177499c2713SBiju Das rtn_on = rcar_pwrc_cpu_on_check(cpu); 178499c2713SBiju Das 179499c2713SBiju Das if (cpu == rcar_boot_mpidr) 180499c2713SBiju Das panic(); 181499c2713SBiju Das 182499c2713SBiju Das if (rtn_on) 183499c2713SBiju Das panic(); 184499c2713SBiju Das 185499c2713SBiju Das rcar_pwrc_cpuoff(cpu); 186499c2713SBiju Das rcar_pwrc_clusteroff(cpu); 187499c2713SBiju Das 188499c2713SBiju Das #endif /* PMIC_ROHM_BD9571 */ 189499c2713SBiju Das wfi(); 190499c2713SBiju Das ERROR("RCAR System Off: operation not handled.\n"); 191499c2713SBiju Das panic(); 192499c2713SBiju Das } 193499c2713SBiju Das 194499c2713SBiju Das static void __dead2 rcar_system_reset(void) 195499c2713SBiju Das { 196499c2713SBiju Das #if PMIC_ROHM_BD9571 197499c2713SBiju Das #if PMIC_LEVEL_MODE 198499c2713SBiju Das #if RCAR_SYSTEM_RESET_KEEPON_DDR 199499c2713SBiju Das uint8_t mode; 200499c2713SBiju Das int32_t error; 201499c2713SBiju Das 202499c2713SBiju Das error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, KEEP10_MAGIC); 203499c2713SBiju Das if (error) { 204499c2713SBiju Das ERROR("Failed send KEEP10 magic ret=%d\n", error); 205499c2713SBiju Das goto done; 206499c2713SBiju Das } 207499c2713SBiju Das 208499c2713SBiju Das error = rcar_iic_dvfs_receive(PMIC, BKUP_MODE_CNT, &mode); 209499c2713SBiju Das if (error) { 210499c2713SBiju Das ERROR("Failed receive BKUP_Mode_Cnt ret=%d\n", error); 211499c2713SBiju Das goto done; 212499c2713SBiju Das } 213499c2713SBiju Das 214499c2713SBiju Das mode |= KEEPON_DDR1C | KEEPON_DDR0C | KEEPON_DDR1 | KEEPON_DDR0; 215499c2713SBiju Das error = rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, mode); 216499c2713SBiju Das if (error) { 217499c2713SBiju Das ERROR("Failed send KEEPON_DDRx ret=%d\n", error); 218499c2713SBiju Das goto done; 219499c2713SBiju Das } 220499c2713SBiju Das 221499c2713SBiju Das rcar_pwrc_set_suspend_to_ram(); 222499c2713SBiju Das done: 223499c2713SBiju Das #else 224499c2713SBiju Das if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF)) 225499c2713SBiju Das ERROR("BL3-1:Failed the SYSTEM-RESET.\n"); 226499c2713SBiju Das #endif 227499c2713SBiju Das #else 228499c2713SBiju Das #if (RCAR_GEN3_ULCB == 1) 229499c2713SBiju Das rcar_cpld_reset_cpu(); 230499c2713SBiju Das #endif 231499c2713SBiju Das #endif 232499c2713SBiju Das #else 233499c2713SBiju Das rcar_pwrc_system_reset(); 234499c2713SBiju Das #endif 235499c2713SBiju Das wfi(); 236499c2713SBiju Das 237499c2713SBiju Das ERROR("RCAR System Reset: operation not handled.\n"); 238499c2713SBiju Das panic(); 239499c2713SBiju Das } 240499c2713SBiju Das 241499c2713SBiju Das static int rcar_validate_power_state(unsigned int power_state, 242499c2713SBiju Das psci_power_state_t *req_state) 243499c2713SBiju Das { 244499c2713SBiju Das unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 245499c2713SBiju Das unsigned int pstate = psci_get_pstate_type(power_state); 246499c2713SBiju Das uint32_t i; 247499c2713SBiju Das 248499c2713SBiju Das if (pstate == PSTATE_TYPE_STANDBY) { 249499c2713SBiju Das if (pwr_lvl != MPIDR_AFFLVL0) 250499c2713SBiju Das return PSCI_E_INVALID_PARAMS; 251499c2713SBiju Das 252499c2713SBiju Das req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE; 253499c2713SBiju Das } else { 254499c2713SBiju Das for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++) 255499c2713SBiju Das req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; 256499c2713SBiju Das } 257499c2713SBiju Das 258499c2713SBiju Das if (psci_get_pstate_id(power_state)) 259499c2713SBiju Das return PSCI_E_INVALID_PARAMS; 260499c2713SBiju Das 261499c2713SBiju Das return PSCI_E_SUCCESS; 262499c2713SBiju Das } 263499c2713SBiju Das 264499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND 265499c2713SBiju Das static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state) 266499c2713SBiju Das { 267499c2713SBiju Das unsigned long mpidr = read_mpidr_el1() & 0x0000ffffU; 268499c2713SBiju Das int i; 269499c2713SBiju Das 270499c2713SBiju Das if (mpidr != rcar_boot_mpidr) 271499c2713SBiju Das goto deny; 272499c2713SBiju Das 273499c2713SBiju Das for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) 274499c2713SBiju Das req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; 275499c2713SBiju Das 276499c2713SBiju Das return; 277499c2713SBiju Das deny: 278499c2713SBiju Das /* deny system suspend entry */ 279499c2713SBiju Das req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSCI_LOCAL_STATE_RUN; 280499c2713SBiju Das for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) 281499c2713SBiju Das req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE; 282499c2713SBiju Das } 283499c2713SBiju Das #endif 284499c2713SBiju Das 285499c2713SBiju Das static const plat_psci_ops_t rcar_plat_psci_ops = { 286499c2713SBiju Das .cpu_standby = rcar_cpu_standby, 287499c2713SBiju Das .pwr_domain_on = rcar_pwr_domain_on, 288499c2713SBiju Das .pwr_domain_off = rcar_pwr_domain_off, 289499c2713SBiju Das .pwr_domain_suspend = rcar_pwr_domain_suspend, 290499c2713SBiju Das .pwr_domain_on_finish = rcar_pwr_domain_on_finish, 291499c2713SBiju Das .pwr_domain_suspend_finish = rcar_pwr_domain_suspend_finish, 292499c2713SBiju Das .system_off = rcar_system_off, 293499c2713SBiju Das .system_reset = rcar_system_reset, 294499c2713SBiju Das .validate_power_state = rcar_validate_power_state, 295499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND 296499c2713SBiju Das .get_sys_suspend_power_state = rcar_get_sys_suspend_power_state, 297499c2713SBiju Das #endif 298499c2713SBiju Das }; 299499c2713SBiju Das 300499c2713SBiju Das int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) 301499c2713SBiju Das { 302499c2713SBiju Das *psci_ops = &rcar_plat_psci_ops; 303499c2713SBiju Das rcar_sec_entrypoint = sec_entrypoint; 304499c2713SBiju Das 305499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND 306499c2713SBiju Das rcar_pwrc_init_suspend_to_ram(); 307499c2713SBiju Das #endif 308499c2713SBiju Das return 0; 309499c2713SBiju Das } 310499c2713SBiju Das 311