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 <assert.h> 9 #include <mmio.h> 10 #include <platform.h> 11 #include <platform_def.h> 12 #include <../hikey960_def.h> 13 #include <hisi_ipc.h> 14 #include "hisi_pwrc.h" 15 16 17 /* resource lock api */ 18 #define RES0_LOCK_BASE (SOC_PCTRL_RESOURCE0_LOCK_ADDR(PCTRL_BASE)) 19 #define RES1_LOCK_BASE (SOC_PCTRL_RESOURCE1_LOCK_ADDR(PCTRL_BASE)) 20 #define RES2_LOCK_BASE (SOC_PCTRL_RESOURCE2_LOCK_ADDR(PCTRL_BASE)) 21 22 #define LOCK_BIT (0x1 << 28) 23 #define LOCK_ID_MASK (0x7 << 29) 24 #define CPUIDLE_LOCK_ID(core) (0x6 - (core)) 25 #define LOCK_UNLOCK_OFFSET 0x4 26 #define LOCK_STAT_OFFSET 0x8 27 28 #define CLUSTER0_CPUS_ONLINE_MASK (0xF << 16) 29 #define CLUSTER1_CPUS_ONLINE_MASK (0xF << 20) 30 31 /* cpu hotplug flag api */ 32 #define SCTRL_BASE (SOC_ACPU_SCTRL_BASE_ADDR) 33 #define REG_SCBAKDATA3_OFFSET (SOC_SCTRL_SCBAKDATA3_ADDR(SCTRL_BASE)) 34 #define REG_SCBAKDATA8_OFFSET (SOC_SCTRL_SCBAKDATA8_ADDR(SCTRL_BASE)) 35 #define REG_SCBAKDATA9_OFFSET (SOC_SCTRL_SCBAKDATA9_ADDR(SCTRL_BASE)) 36 37 #define CPUIDLE_FLAG_REG(cluster) \ 38 ((cluster == 0) ? REG_SCBAKDATA8_OFFSET : \ 39 REG_SCBAKDATA9_OFFSET) 40 #define CLUSTER_IDLE_BIT BIT(8) 41 #define CLUSTER_IDLE_MASK (CLUSTER_IDLE_BIT | 0x0F) 42 43 #define AP_SUSPEND_FLAG (1 << 16) 44 45 #define CLUSTER_PWDN_IDLE (0<<28) 46 #define CLUSTER_PWDN_HOTPLUG (1<<28) 47 #define CLUSTER_PWDN_SR (2<<28) 48 49 #define CLUSTER0_PDC_OFFSET 0x260 50 #define CLUSTER1_PDC_OFFSET 0x300 51 52 #define PDC_EN_OFFSET 0x0 53 #define PDC_COREPWRINTEN_OFFSET 0x4 54 #define PDC_COREPWRINTSTAT_OFFSET 0x8 55 #define PDC_COREGICMASK_OFFSET 0xc 56 #define PDC_COREPOWERUP_OFFSET 0x10 57 #define PDC_COREPOWERDN_OFFSET 0x14 58 #define PDC_COREPOWERSTAT_OFFSET 0x18 59 60 #define PDC_COREPWRSTAT_MASK (0XFFFF) 61 62 enum pdc_gic_mask { 63 PDC_MASK_GIC_WAKE_IRQ, 64 PDC_UNMASK_GIC_WAKE_IRQ 65 }; 66 67 enum pdc_finish_int_mask { 68 PDC_DISABLE_FINISH_INT, 69 PDC_ENABLE_FINISH_INT 70 }; 71 72 static void hisi_resource_lock(unsigned int lockid, unsigned int offset) 73 { 74 unsigned int lock_id = (lockid << 29); 75 unsigned int lock_val = lock_id | LOCK_BIT; 76 unsigned int lock_state; 77 78 do { 79 mmio_write_32(offset, lock_val); 80 lock_state = mmio_read_32(LOCK_STAT_OFFSET + (uintptr_t)offset); 81 } while ((lock_state & LOCK_ID_MASK) != lock_id); 82 } 83 84 static void hisi_resource_unlock(unsigned int lockid, unsigned int offset) 85 { 86 unsigned int lock_val = (lockid << 29) | LOCK_BIT; 87 88 mmio_write_32((LOCK_UNLOCK_OFFSET + (uintptr_t)offset), lock_val); 89 } 90 91 92 static void hisi_cpuhotplug_lock(unsigned int cluster, unsigned int core) 93 { 94 unsigned int lock_id; 95 96 lock_id = (cluster << 2) + core; 97 98 hisi_resource_lock(lock_id, RES2_LOCK_BASE); 99 } 100 101 static void hisi_cpuhotplug_unlock(unsigned int cluster, unsigned int core) 102 { 103 unsigned int lock_id; 104 105 lock_id = (cluster << 2) + core; 106 107 hisi_resource_unlock(lock_id, RES2_LOCK_BASE); 108 } 109 110 /* get the resource lock */ 111 void hisi_cpuidle_lock(unsigned int cluster, unsigned int core) 112 { 113 unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE); 114 115 hisi_resource_lock(CPUIDLE_LOCK_ID(core), offset); 116 } 117 118 /* release the resource lock */ 119 void hisi_cpuidle_unlock(unsigned int cluster, unsigned int core) 120 { 121 unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE); 122 123 hisi_resource_unlock(CPUIDLE_LOCK_ID(core), offset); 124 } 125 126 unsigned int hisi_get_cpuidle_flag(unsigned int cluster) 127 { 128 unsigned int val; 129 130 val = mmio_read_32(CPUIDLE_FLAG_REG(cluster)); 131 val &= 0xF; 132 133 return val; 134 } 135 136 void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core) 137 { 138 mmio_setbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core)); 139 } 140 141 void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core) 142 { 143 mmio_clrbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core)); 144 145 } 146 147 int hisi_test_ap_suspend_flag(unsigned int cluster) 148 { 149 unsigned int val; 150 151 val = mmio_read_32(CPUIDLE_FLAG_REG(cluster)); 152 val &= AP_SUSPEND_FLAG; 153 return !!val; 154 } 155 156 void hisi_set_cluster_pwdn_flag(unsigned int cluster, 157 unsigned int core, unsigned int value) 158 { 159 unsigned int val; 160 161 hisi_cpuhotplug_lock(cluster, core); 162 163 val = mmio_read_32(REG_SCBAKDATA3_OFFSET); 164 val = (value << (cluster << 1)) | (val & 0xFFFFFFF); 165 mmio_write_32(REG_SCBAKDATA3_OFFSET, val); 166 167 hisi_cpuhotplug_unlock(cluster, core); 168 } 169 170 unsigned int hisi_get_cpu_boot_flag(unsigned int cluster, unsigned int core) 171 { 172 unsigned int val; 173 174 hisi_cpuhotplug_lock(cluster, core); 175 val = mmio_read_32(REG_SCBAKDATA3_OFFSET); 176 val = val >> (16 + (cluster << 2)); 177 val &= 0xF; 178 hisi_cpuhotplug_unlock(cluster, core); 179 180 return val; 181 } 182 183 unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core) 184 { 185 unsigned int val; 186 187 hisi_cpuhotplug_lock(cluster, core); 188 val = mmio_read_32(REG_SCBAKDATA3_OFFSET); 189 val = val >> (16 + (cluster << 2)); 190 val &= 0xF; 191 hisi_cpuhotplug_unlock(cluster, core); 192 193 if (val) 194 return 0; 195 else 196 return 1; 197 } 198 199 void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core) 200 { 201 unsigned int flag = BIT((cluster<<2) + core + 16); 202 203 hisi_cpuhotplug_lock(cluster, core); 204 205 mmio_setbits_32(REG_SCBAKDATA3_OFFSET, flag); 206 207 hisi_cpuhotplug_unlock(cluster, core); 208 } 209 210 void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core) 211 { 212 unsigned int flag = BIT((cluster<<2) + core + 16); 213 214 hisi_cpuhotplug_lock(cluster, core); 215 216 mmio_clrbits_32(REG_SCBAKDATA3_OFFSET, flag); 217 218 hisi_cpuhotplug_unlock(cluster, core); 219 } 220 221 int cluster_is_powered_on(unsigned int cluster) 222 { 223 unsigned int val = mmio_read_32(REG_SCBAKDATA3_OFFSET); 224 int ret; 225 226 if (cluster == 0) 227 ret = val & CLUSTER0_CPUS_ONLINE_MASK; 228 else 229 ret = val & CLUSTER1_CPUS_ONLINE_MASK; 230 231 return !!ret; 232 } 233 234 static void *hisi_get_pdc_addr(unsigned int cluster) 235 { 236 void *pdc_base_addr; 237 uintptr_t addr; 238 239 if (cluster == 0) 240 addr = SOC_CRGPERIPH_A53_PDCEN_ADDR(CRG_BASE); 241 else 242 addr = SOC_CRGPERIPH_MAIA_PDCEN_ADDR(CRG_BASE); 243 pdc_base_addr = (void *)addr; 244 245 return pdc_base_addr; 246 } 247 248 static unsigned int hisi_get_pdc_stat(unsigned int cluster) 249 { 250 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 251 unsigned int val; 252 253 val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPOWERSTAT_OFFSET); 254 255 return val; 256 } 257 258 int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core) 259 { 260 unsigned int mask = 0xf << (core * 4); 261 unsigned int pdc_stat = hisi_get_pdc_stat(cluster); 262 unsigned int boot_flag = hisi_get_cpu_boot_flag(cluster, core); 263 unsigned int cpuidle_flag = hisi_get_cpuidle_flag(cluster); 264 265 mask = (PDC_COREPWRSTAT_MASK & (~mask)); 266 pdc_stat &= mask; 267 268 if ((boot_flag ^ cpuidle_flag) || pdc_stat) 269 return 0; 270 else 271 return 1; 272 } 273 274 void hisi_disable_pdc(unsigned int cluster) 275 { 276 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 277 278 mmio_write_32((uintptr_t)pdc_base_addr, 0x0); 279 } 280 281 void hisi_enable_pdc(unsigned int cluster) 282 { 283 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 284 285 mmio_write_32((uintptr_t)pdc_base_addr, 0x1); 286 } 287 288 static inline void hisi_pdc_set_intmask(void *pdc_base_addr, 289 unsigned int core, 290 enum pdc_finish_int_mask intmask) 291 { 292 unsigned int val; 293 294 val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET); 295 if (intmask == PDC_ENABLE_FINISH_INT) 296 val |= BIT(core); 297 else 298 val &= ~BIT(core); 299 300 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, val); 301 } 302 303 static inline void hisi_pdc_set_gicmask(void *pdc_base_addr, 304 unsigned int core, 305 enum pdc_gic_mask gicmask) 306 { 307 unsigned int val; 308 309 val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET); 310 if (gicmask == PDC_MASK_GIC_WAKE_IRQ) 311 val |= BIT(core); 312 else 313 val &= ~BIT(core); 314 315 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET, val); 316 } 317 318 void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster) 319 { 320 int i; 321 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 322 323 for (i = 0; i < 4; i++) 324 hisi_pdc_set_gicmask(pdc_base_addr, i, PDC_MASK_GIC_WAKE_IRQ); 325 } 326 327 static void hisi_pdc_powerup_core(unsigned int cluster, unsigned int core, 328 enum pdc_gic_mask gicmask, 329 enum pdc_finish_int_mask intmask) 330 { 331 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 332 333 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERUP_OFFSET, 334 BIT(core)); 335 } 336 337 static void hisi_pdc_powerdn_core(unsigned int cluster, unsigned int core, 338 enum pdc_gic_mask gicmask, 339 enum pdc_finish_int_mask intmask) 340 { 341 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 342 343 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET, 344 BIT(core)); 345 } 346 347 void hisi_powerup_core(unsigned int cluster, unsigned int core) 348 { 349 hisi_pdc_powerup_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ, 350 PDC_DISABLE_FINISH_INT); 351 } 352 353 void hisi_powerdn_core(unsigned int cluster, unsigned int core) 354 { 355 hisi_pdc_powerdn_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ, 356 PDC_DISABLE_FINISH_INT); 357 } 358 359 void hisi_powerup_cluster(unsigned int cluster, unsigned int core) 360 { 361 hisi_ipc_pm_on_off(core, cluster, PM_ON); 362 } 363 364 void hisi_powerdn_cluster(unsigned int cluster, unsigned int core) 365 { 366 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 367 368 hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_HOTPLUG); 369 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, 370 (0x10001 << core)); 371 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET, 372 BIT(core)); 373 } 374 375 void hisi_enter_core_idle(unsigned int cluster, unsigned int core) 376 { 377 hisi_pdc_powerdn_core(cluster, core, PDC_UNMASK_GIC_WAKE_IRQ, 378 PDC_DISABLE_FINISH_INT); 379 } 380 381 void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core) 382 { 383 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 384 385 hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_IDLE); 386 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, 387 (0x10001 << core)); 388 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET, 389 BIT(core)); 390 } 391 392 void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core) 393 { 394 hisi_ipc_pm_suspend(core, cluster, 0x3); 395 } 396