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