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