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