1 /* 2 * Copyright (c) 2014-2015, Linaro Ltd and Contributors. All rights reserved. 3 * Copyright (c) 2014-2015, Hisilicon Ltd and Contributors. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * Neither the name of ARM nor the names of its contributors may be used 16 * to endorse or promote products derived from this software without specific 17 * prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <hisi_ipc.h> 33 #include <hisi_sram_map.h> 34 #include <mmio.h> 35 #include <platform_def.h> 36 #include <stdio.h> 37 #include <stdarg.h> 38 #include <string.h> 39 40 #define BIT(x) (0x1 << (x)) 41 42 static int _ipc_init = 0; 43 44 static unsigned int cpu_ipc_num[PLATFORM_CLUSTER_COUNT][PLATFORM_CORE_COUNT_PER_CLUSTER] = { 45 { 46 HISI_IPC_MCU_INT_SRC_ACPU0_PD, 47 HISI_IPC_MCU_INT_SRC_ACPU1_PD, 48 HISI_IPC_MCU_INT_SRC_ACPU2_PD, 49 HISI_IPC_MCU_INT_SRC_ACPU3_PD, 50 }, 51 { 52 HISI_IPC_MCU_INT_SRC_ACPU4_PD, 53 HISI_IPC_MCU_INT_SRC_ACPU5_PD, 54 HISI_IPC_MCU_INT_SRC_ACPU6_PD, 55 HISI_IPC_MCU_INT_SRC_ACPU7_PD, 56 } 57 }; 58 59 int hisi_cpus_pd_in_cluster_besides_curr(unsigned int cpu, 60 unsigned int cluster) 61 { 62 unsigned int val = 0, cpu_val = 0; 63 int i; 64 65 val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); 66 val = val >> (cluster * 16); 67 68 for (i = 0; i < PLATFORM_CORE_COUNT_PER_CLUSTER; i++) { 69 70 if (cpu == i) 71 continue; 72 73 cpu_val = (val >> (i * 4)) & 0xF; 74 if (cpu_val == 0x8) 75 return 0; 76 } 77 78 return 1; 79 } 80 81 int hisi_cpus_powered_off_besides_curr(unsigned int cpu) 82 { 83 unsigned int val; 84 85 val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); 86 return (val == (0x8 << (cpu * 4))); 87 } 88 89 static void hisi_ipc_send(unsigned int ipc_num) 90 { 91 if (!_ipc_init) { 92 printf("error ipc base is null!!!\n"); 93 return; 94 } 95 96 mmio_write_32(HISI_IPC_CPU_RAW_INT_ADDR, 1 << ipc_num); 97 } 98 99 void hisi_ipc_spin_lock(unsigned int signal) 100 { 101 unsigned int hs_ctrl; 102 103 if (signal >= HISI_IPC_INT_SRC_NUM) 104 return; 105 106 do { 107 hs_ctrl = mmio_read_32(HISI_IPC_ACPU_CTRL(signal)); 108 } while (hs_ctrl); 109 } 110 111 void hisi_ipc_spin_unlock(unsigned int signal) 112 { 113 if (signal >= HISI_IPC_INT_SRC_NUM) 114 return; 115 116 mmio_write_32(HISI_IPC_ACPU_CTRL(signal), 0); 117 } 118 119 void hisi_ipc_cpu_on_off(unsigned int cpu, unsigned int cluster, 120 unsigned int mode) 121 { 122 unsigned int val = 0; 123 unsigned int offset; 124 125 if (mode == HISI_IPC_PM_ON) 126 offset = cluster * 16 + cpu * 4; 127 else 128 offset = cluster * 16 + cpu * 4 + 1; 129 130 hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); 131 val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); 132 val |= (0x01 << offset); 133 mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, val); 134 hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); 135 136 hisi_ipc_send(cpu_ipc_num[cluster][cpu]); 137 } 138 139 void hisi_ipc_cpu_on(unsigned int cpu, unsigned int cluster) 140 { 141 hisi_ipc_cpu_on_off(cpu, cluster, HISI_IPC_PM_ON); 142 } 143 144 void hisi_ipc_cpu_off(unsigned int cpu, unsigned int cluster) 145 { 146 hisi_ipc_cpu_on_off(cpu, cluster, HISI_IPC_PM_OFF); 147 } 148 149 void hisi_ipc_cluster_on_off(unsigned int cpu, unsigned int cluster, 150 unsigned int mode) 151 { 152 unsigned int val = 0; 153 unsigned int offset; 154 155 if (mode == HISI_IPC_PM_ON) 156 offset = cluster * 4; 157 else 158 offset = cluster * 4 + 1; 159 160 hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); 161 val = mmio_read_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR); 162 val |= (0x01 << offset); 163 mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, val); 164 hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); 165 166 hisi_ipc_send(cpu_ipc_num[cluster][cpu]); 167 } 168 169 void hisi_ipc_cluster_on(unsigned int cpu, unsigned int cluster) 170 { 171 hisi_ipc_cluster_on_off(cpu, cluster, HISI_IPC_PM_ON); 172 } 173 174 void hisi_ipc_cluster_off(unsigned int cpu, unsigned int cluster) 175 { 176 hisi_ipc_cluster_on_off(cpu, cluster, HISI_IPC_PM_OFF); 177 } 178 179 void hisi_ipc_cpu_suspend(unsigned int cpu, unsigned int cluster) 180 { 181 unsigned int val = 0; 182 unsigned int offset; 183 184 offset = cluster * 16 + cpu * 4 + 2; 185 186 hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); 187 val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); 188 val |= (0x01 << offset); 189 mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, val); 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_cluster_suspend(unsigned int cpu, unsigned int cluster) 196 { 197 unsigned int val; 198 unsigned int offset; 199 200 offset = cluster * 4 + 1; 201 202 hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); 203 if (hisi_cpus_pd_in_cluster_besides_curr(cpu, cluster)) { 204 val = mmio_read_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR); 205 val |= (0x01 << offset); 206 mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, val); 207 } 208 hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); 209 210 hisi_ipc_send(cpu_ipc_num[cluster][cpu]); 211 } 212 213 void hisi_ipc_psci_system_off(void) 214 { 215 hisi_ipc_send(HISI_IPC_MCU_INT_SRC_ACPU_PD); 216 } 217 218 int hisi_ipc_init(void) 219 { 220 _ipc_init = 1; 221 222 mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, 0x8); 223 mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, 0x8); 224 return 0; 225 } 226