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