1 /* 2 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <stdarg.h> 8 #include <stdio.h> 9 #include <string.h> 10 11 #include <platform_def.h> 12 13 #include <arch_helpers.h> 14 #include <common/debug.h> 15 #include <lib/mmio.h> 16 17 #include <hisi_ipc.h> 18 #include <hisi_sram_map.h> 19 20 static int ipc_init; 21 22 static unsigned int cpu_ipc_num[PLATFORM_CLUSTER_COUNT][PLATFORM_CORE_COUNT_PER_CLUSTER] = { 23 { 24 HISI_IPC_MCU_INT_SRC_ACPU0_PD, 25 HISI_IPC_MCU_INT_SRC_ACPU1_PD, 26 HISI_IPC_MCU_INT_SRC_ACPU2_PD, 27 HISI_IPC_MCU_INT_SRC_ACPU3_PD, 28 }, 29 { 30 HISI_IPC_MCU_INT_SRC_ACPU4_PD, 31 HISI_IPC_MCU_INT_SRC_ACPU5_PD, 32 HISI_IPC_MCU_INT_SRC_ACPU6_PD, 33 HISI_IPC_MCU_INT_SRC_ACPU7_PD, 34 } 35 }; 36 37 int hisi_cpus_pd_in_cluster_besides_curr(unsigned int cpu, 38 unsigned int cluster) 39 { 40 unsigned int val = 0, cpu_val = 0; 41 int i; 42 43 val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); 44 val = val >> (cluster * 16); 45 46 for (i = 0; i < PLATFORM_CORE_COUNT_PER_CLUSTER; i++) { 47 48 if (cpu == i) 49 continue; 50 51 cpu_val = (val >> (i * 4)) & 0xF; 52 if (cpu_val == 0x8) 53 return 0; 54 } 55 56 return 1; 57 } 58 59 int hisi_cpus_powered_off_besides_curr(unsigned int cpu) 60 { 61 unsigned int val; 62 63 val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); 64 return (val == (0x8 << (cpu * 4))); 65 } 66 67 static void hisi_ipc_send(unsigned int ipc_num) 68 { 69 if (!ipc_init) { 70 printf("error ipc base is null!!!\n"); 71 return; 72 } 73 74 mmio_write_32(HISI_IPC_CPU_RAW_INT_ADDR, 1 << ipc_num); 75 } 76 77 void hisi_ipc_spin_lock(unsigned int signal) 78 { 79 unsigned int hs_ctrl; 80 81 if (signal >= HISI_IPC_INT_SRC_NUM) 82 return; 83 84 do { 85 hs_ctrl = mmio_read_32(HISI_IPC_ACPU_CTRL(signal)); 86 } while (hs_ctrl); 87 } 88 89 void hisi_ipc_spin_unlock(unsigned int signal) 90 { 91 if (signal >= HISI_IPC_INT_SRC_NUM) 92 return; 93 94 mmio_write_32(HISI_IPC_ACPU_CTRL(signal), 0); 95 } 96 97 void hisi_ipc_cpu_on_off(unsigned int cpu, unsigned int cluster, 98 unsigned int mode) 99 { 100 unsigned int val = 0; 101 unsigned int offset; 102 103 if (mode == HISI_IPC_PM_ON) 104 offset = cluster * 16 + cpu * 4; 105 else 106 offset = cluster * 16 + cpu * 4 + 1; 107 108 hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); 109 val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); 110 val |= (0x01 << offset); 111 mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, val); 112 isb(); 113 dsb(); 114 hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); 115 116 hisi_ipc_send(cpu_ipc_num[cluster][cpu]); 117 } 118 119 void hisi_ipc_cpu_on(unsigned int cpu, unsigned int cluster) 120 { 121 hisi_ipc_cpu_on_off(cpu, cluster, HISI_IPC_PM_ON); 122 } 123 124 void hisi_ipc_cpu_off(unsigned int cpu, unsigned int cluster) 125 { 126 hisi_ipc_cpu_on_off(cpu, cluster, HISI_IPC_PM_OFF); 127 } 128 129 void hisi_ipc_cluster_on_off(unsigned int cpu, unsigned int cluster, 130 unsigned int mode) 131 { 132 unsigned int val = 0; 133 unsigned int offset; 134 135 if (mode == HISI_IPC_PM_ON) 136 offset = cluster * 4; 137 else 138 offset = cluster * 4 + 1; 139 140 hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); 141 val = mmio_read_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR); 142 val |= (0x01 << offset); 143 mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, val); 144 isb(); 145 dsb(); 146 hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); 147 148 hisi_ipc_send(cpu_ipc_num[cluster][cpu]); 149 } 150 151 void hisi_ipc_cluster_on(unsigned int cpu, unsigned int cluster) 152 { 153 hisi_ipc_cluster_on_off(cpu, cluster, HISI_IPC_PM_ON); 154 } 155 156 void hisi_ipc_cluster_off(unsigned int cpu, unsigned int cluster) 157 { 158 hisi_ipc_cluster_on_off(cpu, cluster, HISI_IPC_PM_OFF); 159 } 160 161 void hisi_ipc_cpu_suspend(unsigned int cpu, unsigned int cluster) 162 { 163 unsigned int val = 0; 164 unsigned int offset; 165 166 offset = cluster * 16 + cpu * 4 + 2; 167 168 hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); 169 val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); 170 val |= (0x01 << offset); 171 mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, val); 172 hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); 173 174 hisi_ipc_send(cpu_ipc_num[cluster][cpu]); 175 } 176 177 void hisi_ipc_cluster_suspend(unsigned int cpu, unsigned int cluster) 178 { 179 unsigned int val; 180 unsigned int offset; 181 182 offset = cluster * 4 + 1; 183 184 hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); 185 if (hisi_cpus_pd_in_cluster_besides_curr(cpu, cluster)) { 186 val = mmio_read_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR); 187 val |= (0x01 << offset); 188 mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, val); 189 } 190 hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); 191 192 hisi_ipc_send(cpu_ipc_num[cluster][cpu]); 193 } 194 195 void hisi_ipc_psci_system_off(void) 196 { 197 hisi_ipc_send(HISI_IPC_MCU_INT_SRC_ACPU_PD); 198 } 199 200 int hisi_ipc_init(void) 201 { 202 ipc_init = 1; 203 204 mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, 0x8); 205 mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, 0x8); 206 return 0; 207 } 208