1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu 9*91f16700Schasinglulu #include <arch_helpers.h> 10*91f16700Schasinglulu #include <common/debug.h> 11*91f16700Schasinglulu #include <errno.h> 12*91f16700Schasinglulu #include <lib/mmio.h> 13*91f16700Schasinglulu #include <lib/psci/psci.h> 14*91f16700Schasinglulu 15*91f16700Schasinglulu #include "uniphier.h" 16*91f16700Schasinglulu 17*91f16700Schasinglulu #define UNIPHIER_ROM_RSV0 0x0 18*91f16700Schasinglulu 19*91f16700Schasinglulu #define UNIPHIER_SLFRSTSEL 0x10 20*91f16700Schasinglulu #define UNIPHIER_SLFRSTSEL_MASK GENMASK(1, 0) 21*91f16700Schasinglulu #define UNIPHIER_SLFRSTCTL 0x14 22*91f16700Schasinglulu #define UNIPHIER_SLFRSTCTL_RST BIT(0) 23*91f16700Schasinglulu 24*91f16700Schasinglulu #define MPIDR_AFFINITY_INVALID ((u_register_t)-1) 25*91f16700Schasinglulu 26*91f16700Schasinglulu static uintptr_t uniphier_rom_rsv_base; 27*91f16700Schasinglulu static uintptr_t uniphier_slfrst_base; 28*91f16700Schasinglulu 29*91f16700Schasinglulu uintptr_t uniphier_sec_entrypoint; 30*91f16700Schasinglulu 31*91f16700Schasinglulu void uniphier_warmboot_entrypoint(void); 32*91f16700Schasinglulu void __dead2 uniphier_fake_pwr_down(void); 33*91f16700Schasinglulu u_register_t uniphier_holding_pen_release; 34*91f16700Schasinglulu static int uniphier_psci_scp_mode; 35*91f16700Schasinglulu 36*91f16700Schasinglulu static int uniphier_psci_pwr_domain_on(u_register_t mpidr) 37*91f16700Schasinglulu { 38*91f16700Schasinglulu uniphier_holding_pen_release = mpidr; 39*91f16700Schasinglulu flush_dcache_range((uint64_t)&uniphier_holding_pen_release, 40*91f16700Schasinglulu sizeof(uniphier_holding_pen_release)); 41*91f16700Schasinglulu 42*91f16700Schasinglulu mmio_write_64(uniphier_rom_rsv_base + UNIPHIER_ROM_RSV0, 43*91f16700Schasinglulu (uint64_t)&uniphier_warmboot_entrypoint); 44*91f16700Schasinglulu sev(); 45*91f16700Schasinglulu 46*91f16700Schasinglulu return PSCI_E_SUCCESS; 47*91f16700Schasinglulu } 48*91f16700Schasinglulu 49*91f16700Schasinglulu static void uniphier_psci_pwr_domain_off(const psci_power_state_t *target_state) 50*91f16700Schasinglulu { 51*91f16700Schasinglulu uniphier_gic_cpuif_disable(); 52*91f16700Schasinglulu } 53*91f16700Schasinglulu 54*91f16700Schasinglulu static void uniphier_psci_pwr_domain_on_finish( 55*91f16700Schasinglulu const psci_power_state_t *target_state) 56*91f16700Schasinglulu { 57*91f16700Schasinglulu uniphier_gic_pcpu_init(); 58*91f16700Schasinglulu uniphier_gic_cpuif_enable(); 59*91f16700Schasinglulu 60*91f16700Schasinglulu uniphier_cci_enable(); 61*91f16700Schasinglulu } 62*91f16700Schasinglulu 63*91f16700Schasinglulu static void __dead2 uniphier_psci_pwr_domain_pwr_down_wfi( 64*91f16700Schasinglulu const psci_power_state_t *target_state) 65*91f16700Schasinglulu { 66*91f16700Schasinglulu /* 67*91f16700Schasinglulu * The Boot ROM cannot distinguish warm and cold resets. 68*91f16700Schasinglulu * Instead of the CPU reset, fake it. 69*91f16700Schasinglulu */ 70*91f16700Schasinglulu uniphier_holding_pen_release = MPIDR_AFFINITY_INVALID; 71*91f16700Schasinglulu flush_dcache_range((uint64_t)&uniphier_holding_pen_release, 72*91f16700Schasinglulu sizeof(uniphier_holding_pen_release)); 73*91f16700Schasinglulu 74*91f16700Schasinglulu uniphier_fake_pwr_down(); 75*91f16700Schasinglulu } 76*91f16700Schasinglulu 77*91f16700Schasinglulu static void uniphier_self_system_reset(void) 78*91f16700Schasinglulu { 79*91f16700Schasinglulu mmio_clrbits_32(uniphier_slfrst_base + UNIPHIER_SLFRSTSEL, 80*91f16700Schasinglulu UNIPHIER_SLFRSTSEL_MASK); 81*91f16700Schasinglulu mmio_setbits_32(uniphier_slfrst_base + UNIPHIER_SLFRSTCTL, 82*91f16700Schasinglulu UNIPHIER_SLFRSTCTL_RST); 83*91f16700Schasinglulu } 84*91f16700Schasinglulu 85*91f16700Schasinglulu static void __dead2 uniphier_psci_system_off(void) 86*91f16700Schasinglulu { 87*91f16700Schasinglulu if (uniphier_psci_scp_mode) { 88*91f16700Schasinglulu uniphier_scp_system_off(); 89*91f16700Schasinglulu } else { 90*91f16700Schasinglulu NOTICE("SCP is disabled; can't shutdown the system.\n"); 91*91f16700Schasinglulu NOTICE("Resetting the system instead.\n"); 92*91f16700Schasinglulu uniphier_self_system_reset(); 93*91f16700Schasinglulu } 94*91f16700Schasinglulu 95*91f16700Schasinglulu wfi(); 96*91f16700Schasinglulu ERROR("UniPhier System Off: operation not handled.\n"); 97*91f16700Schasinglulu panic(); 98*91f16700Schasinglulu } 99*91f16700Schasinglulu 100*91f16700Schasinglulu static void __dead2 uniphier_psci_system_reset(void) 101*91f16700Schasinglulu { 102*91f16700Schasinglulu if (uniphier_psci_scp_mode) 103*91f16700Schasinglulu uniphier_scp_system_reset(); 104*91f16700Schasinglulu else 105*91f16700Schasinglulu uniphier_self_system_reset(); 106*91f16700Schasinglulu 107*91f16700Schasinglulu wfi(); 108*91f16700Schasinglulu ERROR("UniPhier System Reset: operation not handled.\n"); 109*91f16700Schasinglulu panic(); 110*91f16700Schasinglulu } 111*91f16700Schasinglulu 112*91f16700Schasinglulu static const struct plat_psci_ops uniphier_psci_ops = { 113*91f16700Schasinglulu .pwr_domain_on = uniphier_psci_pwr_domain_on, 114*91f16700Schasinglulu .pwr_domain_off = uniphier_psci_pwr_domain_off, 115*91f16700Schasinglulu .pwr_domain_on_finish = uniphier_psci_pwr_domain_on_finish, 116*91f16700Schasinglulu .pwr_domain_pwr_down_wfi = uniphier_psci_pwr_domain_pwr_down_wfi, 117*91f16700Schasinglulu .system_off = uniphier_psci_system_off, 118*91f16700Schasinglulu .system_reset = uniphier_psci_system_reset, 119*91f16700Schasinglulu }; 120*91f16700Schasinglulu 121*91f16700Schasinglulu int plat_setup_psci_ops(uintptr_t sec_entrypoint, 122*91f16700Schasinglulu const struct plat_psci_ops **psci_ops) 123*91f16700Schasinglulu { 124*91f16700Schasinglulu uniphier_sec_entrypoint = sec_entrypoint; 125*91f16700Schasinglulu flush_dcache_range((uint64_t)&uniphier_sec_entrypoint, 126*91f16700Schasinglulu sizeof(uniphier_sec_entrypoint)); 127*91f16700Schasinglulu 128*91f16700Schasinglulu *psci_ops = &uniphier_psci_ops; 129*91f16700Schasinglulu 130*91f16700Schasinglulu return 0; 131*91f16700Schasinglulu } 132*91f16700Schasinglulu 133*91f16700Schasinglulu struct uniphier_psci_ctrl_base { 134*91f16700Schasinglulu uintptr_t rom_rsv_base; 135*91f16700Schasinglulu uintptr_t slfrst_base; 136*91f16700Schasinglulu }; 137*91f16700Schasinglulu 138*91f16700Schasinglulu static const struct uniphier_psci_ctrl_base uniphier_psci_ctrl_base[] = { 139*91f16700Schasinglulu [UNIPHIER_SOC_LD11] = { 140*91f16700Schasinglulu .rom_rsv_base = 0x59801200, 141*91f16700Schasinglulu .slfrst_base = 0x61843000, 142*91f16700Schasinglulu }, 143*91f16700Schasinglulu [UNIPHIER_SOC_LD20] = { 144*91f16700Schasinglulu .rom_rsv_base = 0x59801200, 145*91f16700Schasinglulu .slfrst_base = 0x61843000, 146*91f16700Schasinglulu }, 147*91f16700Schasinglulu [UNIPHIER_SOC_PXS3] = { 148*91f16700Schasinglulu .rom_rsv_base = 0x59801200, 149*91f16700Schasinglulu .slfrst_base = 0x61843000, 150*91f16700Schasinglulu }, 151*91f16700Schasinglulu }; 152*91f16700Schasinglulu 153*91f16700Schasinglulu void uniphier_psci_init(unsigned int soc) 154*91f16700Schasinglulu { 155*91f16700Schasinglulu assert(soc < ARRAY_SIZE(uniphier_psci_ctrl_base)); 156*91f16700Schasinglulu uniphier_rom_rsv_base = uniphier_psci_ctrl_base[soc].rom_rsv_base; 157*91f16700Schasinglulu uniphier_slfrst_base = uniphier_psci_ctrl_base[soc].slfrst_base; 158*91f16700Schasinglulu 159*91f16700Schasinglulu if (uniphier_get_boot_master(soc) == UNIPHIER_BOOT_MASTER_SCP) { 160*91f16700Schasinglulu uniphier_psci_scp_mode = uniphier_scp_is_running(); 161*91f16700Schasinglulu flush_dcache_range((uint64_t)&uniphier_psci_scp_mode, 162*91f16700Schasinglulu sizeof(uniphier_psci_scp_mode)); 163*91f16700Schasinglulu 164*91f16700Schasinglulu if (uniphier_psci_scp_mode) 165*91f16700Schasinglulu uniphier_scp_open_com(); 166*91f16700Schasinglulu } 167*91f16700Schasinglulu } 168