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