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