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